Merge
authorduke
Wed, 05 Jul 2017 22:32:06 +0200
changeset 42395 c80058e8983e
parent 42394 285ea8081752 (current diff)
parent 42387 9107477607ea (diff)
child 42401 925e4d87ebac
Merge
hotspot/test/runtime/modules/JVMCanReadModule.java
hotspot/test/runtime/modules/JVMIsExportedToModule.java
hotspot/test/serviceability/jdwp/JdwpCanReadCmd.java
hotspot/test/serviceability/jdwp/JdwpCanReadReply.java
jdk/src/java.base/share/classes/java/lang/module/Dependence.java
jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java
jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java
jdk/test/java/awt/Focus/DisposedWindow/DisposeDialogNotActivateOwnerTest/DisposeDialogNotActivateOwnerTest.html
jdk/test/java/lang/Class/getResource/src/m3/module-info.java
jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java
jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java
jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java
jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java
jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java
jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java
jdk/test/java/net/Authenticator/B4933582.sh
jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java
jdk/test/java/util/ServiceLoader/Basic.java
jdk/test/java/util/ServiceLoader/FooProvider1.java
jdk/test/java/util/ServiceLoader/FooProvider2.java
jdk/test/java/util/ServiceLoader/FooProvider3.java
jdk/test/java/util/ServiceLoader/FooService.java
jdk/test/java/util/ServiceLoader/Load.java
jdk/test/java/util/ServiceLoader/basic.sh
jdk/test/java/util/ServiceLoader/modules/MiscTests.java
jdk/test/java/util/ServiceLoader/modules/ServicesTest.java
jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java
jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java
jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java
jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java
jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java
jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java
make/CreateHgtipFiles.gmk
nashorn/test/script/currently-failing/JDK-8130127.js
nashorn/test/script/currently-failing/JDK-8130127.js.EXPECTED
--- a/.hgignore	Fri Dec 02 10:52:51 2016 -0800
+++ b/.hgignore	Wed Jul 05 22:32:06 2017 +0200
@@ -3,8 +3,7 @@
 ^.idea/
 nbproject/private/
 ^webrev
-^.hgtip
-^.bridge2
+^.src-rev$
 ^.jib/
 .DS_Store
 .metadata/
--- a/.hgtags-top-repo	Fri Dec 02 10:52:51 2016 -0800
+++ b/.hgtags-top-repo	Wed Jul 05 22:32:06 2017 +0200
@@ -389,3 +389,4 @@
 8d337fd6333e28c48aa87880144b840aad82baaf jdk-9+144
 ff98aa9ec9fae991e426ce5926fc9036d25f5562 jdk-9+145
 a22e2671d88f6b22a4aa82e3966986542ed2a381 jdk-9+146
+5f6920274c48eb00d31afee6c034826a754c13d9 jdk-9+147
--- a/common/autoconf/boot-jdk.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/boot-jdk.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -98,7 +98,7 @@
   fi
 ])
 
-# Test: Is bootjdk explicitely set by command line arguments?
+# Test: Is bootjdk explicitly set by command line arguments?
 AC_DEFUN([BOOTJDK_CHECK_ARGUMENTS],
 [
   if test "x$with_boot_jdk" != x; then
@@ -238,7 +238,7 @@
       $1=$BOOT_JDK/bin/$2
       if test ! -x [$]$1; then
         AC_MSG_RESULT(not found)
-        AC_MSG_NOTICE([Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk])
+        AC_MSG_NOTICE([Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk])
         AC_MSG_ERROR([Could not find $2 in the Boot JDK])
       fi
       AC_MSG_RESULT(ok)
@@ -262,7 +262,7 @@
   # we detected something (if so, the path to the jdk is in BOOT_JDK). But we
   # must check if this is indeed valid; otherwise we'll continue looking.
 
-  # Test: Is bootjdk explicitely set by command line arguments?
+  # Test: Is bootjdk explicitly set by command line arguments?
   BOOTJDK_DO_CHECK([BOOTJDK_CHECK_ARGUMENTS])
   if test "x$with_boot_jdk" != x && test "x$BOOT_JDK_FOUND" = xno; then
     # Having specified an argument which is incorrect will produce an instant failure;
@@ -286,7 +286,7 @@
   if test "x$BOOT_JDK_FOUND" = xno; then
     HELP_MSG_MISSING_DEPENDENCY([openjdk])
     AC_MSG_NOTICE([Could not find a valid Boot JDK. $HELP_MSG])
-    AC_MSG_NOTICE([This might be fixed by explicitely setting --with-boot-jdk])
+    AC_MSG_NOTICE([This might be fixed by explicitly setting --with-boot-jdk])
     AC_MSG_ERROR([Cannot continue])
   fi
 
--- a/common/autoconf/build-performance.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/build-performance.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -217,6 +217,13 @@
 AC_DEFUN([BPERF_SETUP_CCACHE_USAGE],
 [
   if test "x$CCACHE" != x; then
+    if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then
+      HAS_BAD_CCACHE=[`$ECHO $CCACHE_VERSION | \
+          $GREP -e '^1\.' -e '^2\.' -e '^3\.0\.' -e '^3\.1\.'`]
+      if test "x$HAS_BAD_CCACHE" != "x"; then
+        AC_MSG_ERROR([On macosx, ccache 3.2 or later is required, found $CCACHE_VERSION])
+      fi
+    fi
     if test "x$USE_PRECOMPILED_HEADER" = "x1"; then
       HAS_BAD_CCACHE=[`$ECHO $CCACHE_VERSION | \
           $GREP -e '^1.*' -e '^2.*' -e '^3\.0.*' -e '^3\.1\.[0123]$'`]
--- a/common/autoconf/buildjdk-spec.gmk.in	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/buildjdk-spec.gmk.in	Wed Jul 05 22:32:06 2017 +0200
@@ -86,73 +86,13 @@
 # Save speed and disk space by not enabling debug symbols for the buildjdk
 ENABLE_DEBUG_SYMBOLS := false
 
-####################################################
-#
-# Legacy Hotspot support
+# Control wether Hotspot builds gtest tests
+BUILD_GTEST := false
 
-# Legacy setting: OPT or DBG
-VARIANT := OPT
-# Legacy setting: true or false
-FASTDEBUG := false
-# Legacy setting: debugging the class files?
-DEBUG_CLASSFILES := false
+JVM_VARIANTS := server
 
 # Some users still set EXTRA_*FLAGS on the make command line. Must
 # make sure to override that when building buildjdk.
 override EXTRA_CFLAGS :=
 override EXTRA_CXXFLAGS :=
 override EXTRA_LDFLAGS :=
-
-# The HOSTCC/HOSTCXX is Hotspot terminology for the BUILD_CC/BUILD_CXX, i.e. the
-# compiler that produces code that can be run on the build platform.
-HOSTCC := $(BUILD_CC)
-HOSTCXX := $(BUILD_CXX)
-
-# Old name for OPENJDK_TARGET_OS (aix,bsd,hpux,linux,macosx,solaris,windows etc)
-PLATFORM := $(OPENJDK_BUILD_OS)
-# 32 or 64 bit
-ARCH_DATA_MODEL := $(OPENJDK_BUILD_CPU_BITS)
-
-ALT_BOOTDIR := $(BOOT_JDK)
-# Yet another name for arch used for an extra subdir below the jvm lib.
-# Uses i386 and amd64, instead of x86 and x86_64.
-LIBARCH := @OPENJDK_BUILD_CPU_LEGACY_LIB@
-# Set the cpu architecture. Some users still set ARCH on the make command line. Must
-# make sure to override that when building buildjdk.
-override ARCH := $(OPENJDK_BUILD_CPU_ARCH)
-# Legacy setting for building for a 64 bit machine.
-# If yes then this expands to _LP64 := 1
-ifeq ($(OPENJDK_BUILD_CPU_BITS), 64)
-  _LP64 := 1
-endif
-
-ALT_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)
-ALT_EXPORT_PATH := $(HOTSPOT_DIST)
-
-JVM_INTERPRETER := @JVM_INTERPRETER@
-ifeq ($(JVM_INTERPRETER), cpp)
-  CC_INTERP=true
-endif
-
-HOTSPOT_MAKE_ARGS := product docs export_product
-
-# Control wether Hotspot builds gtest tests
-BUILD_GTEST := false
-
-USE_PRECOMPILED_HEADER := @USE_PRECOMPILED_HEADER@
-
-# Hotspot expects the variable FULL_DEBUG_SYMBOLS=1/0 to control debug symbols
-# creation.
-FULL_DEBUG_SYMBOLS := 0
-ZIP_DEBUGINFO_FILES := 0
-# Disable stripping
-STRIP_POLICY := none
-
-JVM_VARIANTS := server
-JVM_VARIANT_SERVER := true
-JVM_VARIANT_CLIENT := false
-JVM_VARIANT_MINIMAL1 := false
-JVM_VARIANT_KERNEL := false
-JVM_VARIANT_ZERO := false
-JVM_VARIANT_ZEROSHARK := false
-JVM_VARIANT_CORE := false
--- a/common/autoconf/configure.ac	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/configure.ac	Wed Jul 05 22:32:06 2017 +0200
@@ -182,7 +182,6 @@
 
 # Finally do some processing after the detection phase
 TOOLCHAIN_SETUP_BUILD_COMPILERS
-TOOLCHAIN_SETUP_LEGACY
 TOOLCHAIN_MISC_CHECKS
 
 # Setup the JTReg Regression Test Harness.
--- a/common/autoconf/flags.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/flags.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -1378,7 +1378,7 @@
 
   AC_MSG_CHECKING([if native warnings are errors])
   if test "x$enable_warnings_as_errors" = "xyes"; then
-    AC_MSG_RESULT([yes (explicitely set)])
+    AC_MSG_RESULT([yes (explicitly set)])
     WARNINGS_AS_ERRORS=true
   elif test "x$enable_warnings_as_errors" = "xno"; then
     AC_MSG_RESULT([no])
--- a/common/autoconf/generated-configure.sh	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/generated-configure.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -700,8 +700,6 @@
 JVM_FEATURES_server
 INCLUDE_DTRACE
 GCOV_ENABLED
-STRIP_POLICY
-DEBUG_BINARIES
 ZIP_EXTERNAL_DEBUG_SYMBOLS
 COPY_DEBUG_SYMBOLS
 COMPILE_WITH_DEBUG_SYMBOLS
@@ -791,11 +789,6 @@
 HOTSPOT_TOOLCHAIN_TYPE
 USING_BROKEN_SUSE_LD
 PACKAGE_PATH
-USE_CLANG
-HOTSPOT_LD
-HOTSPOT_CXX
-HOTSPOT_RC
-HOTSPOT_MT
 BUILD_AS
 BUILD_LDCXX
 BUILD_LD
@@ -1974,8 +1967,8 @@
   --enable-debug          set the debug level to fastdebug (shorthand for
                           --with-debug-level=fastdebug) [disabled]
   --enable-headless-only  only build headless (no GUI) support [disabled]
-  --enable-unlimited-crypto
-                          Enable unlimited crypto policy [disabled]
+  --disable-unlimited-crypto
+                          Disable unlimited crypto policy [enabled]
   --disable-keep-packaged-modules
                           Do not keep packaged modules in jdk image [enable]
   --enable-static-build   enable static library build [disabled]
@@ -3851,7 +3844,7 @@
 # $1 A command line (typically autoconf macro) to execute
 
 
-# Test: Is bootjdk explicitely set by command line arguments?
+# Test: Is bootjdk explicitly set by command line arguments?
 
 
 # Test: Is $JAVA_HOME set?
@@ -4911,7 +4904,7 @@
 # Minimum supported versions, empty means unspecified
 TOOLCHAIN_MINIMUM_VERSION_clang="3.2"
 TOOLCHAIN_MINIMUM_VERSION_gcc="4.3"
-TOOLCHAIN_MINIMUM_VERSION_microsoft=""
+TOOLCHAIN_MINIMUM_VERSION_microsoft="16.00.30319.01" # VS2010
 TOOLCHAIN_MINIMUM_VERSION_solstudio="5.13"
 TOOLCHAIN_MINIMUM_VERSION_xlc=""
 
@@ -4982,10 +4975,6 @@
 # for this, we can only do this after these have been setup.
 
 
-# Setup legacy variables that are still needed as alternative ways to refer to
-# parts of the toolchain.
-
-
 # Do some additional checks on the detected tools.
 
 
@@ -5093,7 +5082,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1479997904
+DATE_WHEN_GENERATED=1480714260
 
 ###############################################################################
 #
@@ -15523,7 +15512,7 @@
       ;;
   esac
 
-  # ..and setup our own variables. (Do this explicitely to facilitate searching)
+  # ..and setup our own variables. (Do this explicitly to facilitate searching)
   OPENJDK_BUILD_OS="$VAR_OS"
   if test "x$VAR_OS_TYPE" != x; then
     OPENJDK_BUILD_OS_TYPE="$VAR_OS_TYPE"
@@ -15662,7 +15651,7 @@
       ;;
   esac
 
-  # ... and setup our own variables. (Do this explicitely to facilitate searching)
+  # ... and setup our own variables. (Do this explicitly to facilitate searching)
   OPENJDK_TARGET_OS="$VAR_OS"
   if test "x$VAR_OS_TYPE" != x; then
     OPENJDK_TARGET_OS_TYPE="$VAR_OS_TYPE"
@@ -24240,7 +24229,7 @@
 if test "${enable_unlimited_crypto+set}" = set; then :
   enableval=$enable_unlimited_crypto;
 else
-  enable_unlimited_crypto=no
+  enable_unlimited_crypto=yes
 fi
 
   if test "x$enable_unlimited_crypto" = "xyes"; then
@@ -24400,7 +24389,7 @@
         as_fn_error $? "Version string contains + but both 'BUILD' and 'OPT' are missing" "$LINENO" 5
       fi
       # Stop the version part process from setting default values.
-      # We still allow them to explicitely override though.
+      # We still allow them to explicitly override though.
       NO_DEFAULT_VERSION_PARTS=true
     else
       as_fn_error $? "--with-version-string fails to parse as a valid version string: $with_version_string" "$LINENO" 5
@@ -24769,7 +24758,7 @@
   # we detected something (if so, the path to the jdk is in BOOT_JDK). But we
   # must check if this is indeed valid; otherwise we'll continue looking.
 
-  # Test: Is bootjdk explicitely set by command line arguments?
+  # Test: Is bootjdk explicitly set by command line arguments?
 
   if test "x$BOOT_JDK_FOUND" = xno; then
     # Now execute the test
@@ -29887,8 +29876,8 @@
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find a valid Boot JDK. $HELP_MSG" >&5
 $as_echo "$as_me: Could not find a valid Boot JDK. $HELP_MSG" >&6;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: This might be fixed by explicitly setting --with-boot-jdk" >&6;}
     as_fn_error $? "Cannot continue" "$LINENO" 5
   fi
 
@@ -29910,8 +29899,8 @@
       if test ! -x $JAVA; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find java in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -29938,8 +29927,8 @@
       if test ! -x $JAVA; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find java in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -30048,8 +30037,8 @@
       if test ! -x $JAVAC; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find javac in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -30076,8 +30065,8 @@
       if test ! -x $JAVAC; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find javac in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -30186,8 +30175,8 @@
       if test ! -x $JAVAH; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find javah in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -30214,8 +30203,8 @@
       if test ! -x $JAVAH; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find javah in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -30324,8 +30313,8 @@
       if test ! -x $JAR; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find jar in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -30352,8 +30341,8 @@
       if test ! -x $JAR; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find jar in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -30462,8 +30451,8 @@
       if test ! -x $JARSIGNER; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find jarsigner in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -30490,8 +30479,8 @@
       if test ! -x $JARSIGNER; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
 $as_echo "not found" >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&5
-$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitely setting --with-boot-jdk" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&5
+$as_echo "$as_me: Your Boot JDK seems broken. This might be fixed by explicitly setting --with-boot-jdk" >&6;}
         as_fn_error $? "Could not find jarsigner in the Boot JDK" "$LINENO" 5
       fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
@@ -31198,6 +31187,12 @@
   if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then
     IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src"
   fi
+  # Workaround for using different imported module-info.java in Jake due to a
+  # change in format. Remove once new format is standard in JDK 9 and javafx
+  # delivers just that.
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_src_jake"; then
+    IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src_jake $IMPORT_MODULES_SRC"
+  fi
   if test -d "$IMPORT_MODULES_TOPDIR/make"; then
     IMPORT_MODULES_MAKE="$IMPORT_MODULES_TOPDIR/make"
   fi
@@ -33578,9 +33573,11 @@
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     # cc -V output typically looks like
     #     cc: Sun C 5.12 Linux_i386 2011/11/16
+    # or
+    #     cc: Studio 12.5 Sun C 5.14 SunOS_sparc 2016/05/31
     COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1`
     # Check that this is likely to be the Solaris Studio cc.
-    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null
+    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.* Sun $COMPILER_NAME" > /dev/null
     if test $? -ne 0; then
       ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1`
       { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5
@@ -34875,9 +34872,11 @@
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     # cc -V output typically looks like
     #     cc: Sun C 5.12 Linux_i386 2011/11/16
+    # or
+    #     cc: Studio 12.5 Sun C 5.14 SunOS_sparc 2016/05/31
     COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1`
     # Check that this is likely to be the Solaris Studio cc.
-    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null
+    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.* Sun $COMPILER_NAME" > /dev/null
     if test $? -ne 0; then
       ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1`
       { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5
@@ -35261,9 +35260,9 @@
   fi
 
   # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal.
-  if  [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5
-$as_echo "$as_me: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
+  if  [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){4} ]] ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5
+$as_echo "$as_me: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
   fi
 
   if  [[  "[$]CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then
@@ -35271,7 +35270,7 @@
 $as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
   fi
 
-  COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$CC_VERSION_NUMBER"`
+  COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$CC_VERSION_NUMBER"`
 
 
   if test "x$TOOLCHAIN_MINIMUM_VERSION" != x; then
@@ -35329,8 +35328,8 @@
   # Need to assign to a variable since m4 is blocked from modifying parts in [].
   REFERENCE_VERSION=$TOOLCHAIN_MINIMUM_VERSION
 
-  if  [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then
-    as_fn_error $? "Internal error: Cannot compare to $TOOLCHAIN_MINIMUM_VERSION, only three parts (X.Y.Z) is supported" "$LINENO" 5
+  if  [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then
+    as_fn_error $? "Internal error: Cannot compare to $TOOLCHAIN_MINIMUM_VERSION, only four parts (W.X.Y.Z) is supported" "$LINENO" 5
   fi
 
   if  [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then
@@ -35338,7 +35337,7 @@
   fi
 
   # Version comparison method inspired by http://stackoverflow.com/a/24067243
-  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"`
+  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$REFERENCE_VERSION"`
 
   if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then
     :
@@ -46956,9 +46955,11 @@
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     # cc -V output typically looks like
     #     cc: Sun C 5.12 Linux_i386 2011/11/16
+    # or
+    #     cc: Studio 12.5 Sun C 5.14 SunOS_sparc 2016/05/31
     COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1`
     # Check that this is likely to be the Solaris Studio cc.
-    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null
+    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.* Sun $COMPILER_NAME" > /dev/null
     if test $? -ne 0; then
       ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1`
       { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5
@@ -47076,9 +47077,11 @@
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     # cc -V output typically looks like
     #     cc: Sun C 5.12 Linux_i386 2011/11/16
+    # or
+    #     cc: Studio 12.5 Sun C 5.14 SunOS_sparc 2016/05/31
     COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1`
     # Check that this is likely to be the Solaris Studio cc.
-    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null
+    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.* Sun $COMPILER_NAME" > /dev/null
     if test $? -ne 0; then
       ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1`
       { $as_echo "$as_me:${as_lineno-$LINENO}: The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler." >&5
@@ -47198,9 +47201,9 @@
   fi
 
   # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal.
-  if  [[ "[$]BUILD_CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than three parts (X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&5
-$as_echo "$as_me: WARNING: C compiler version number has more than three parts (X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
+  if  [[ "[$]BUILD_CC_VERSION_NUMBER" =~ (.*\.){4} ]] ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&5
+$as_echo "$as_me: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
   fi
 
   if  [[  "[$]BUILD_CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then
@@ -47208,7 +47211,7 @@
 $as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $BUILD_CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
   fi
 
-  OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$BUILD_CC_VERSION_NUMBER"`
+  OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$BUILD_CC_VERSION_NUMBER"`
 
   else
     # If we are not cross compiling, use the normal target compilers for
@@ -47234,9 +47237,9 @@
   fi
 
   # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal.
-  if  [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){3} ]] ; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5
-$as_echo "$as_me: WARNING: C compiler version number has more than three parts (X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
+  if  [[ "[$]CC_VERSION_NUMBER" =~ (.*\.){4} ]] ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&5
+$as_echo "$as_me: WARNING: C compiler version number has more than four parts (W.X.Y.Z): $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
   fi
 
   if  [[  "[$]CC_VERSION_NUMBER" =~ [0-9]{6} ]] ; then
@@ -47244,80 +47247,18 @@
 $as_echo "$as_me: WARNING: C compiler version number has a part larger than 99999: $CC_VERSION_NUMBER. Comparisons might be wrong." >&2;}
   fi
 
-  OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$CC_VERSION_NUMBER"`
-
-  fi
-
-
-
-
-
-
-
-
-
-
-
-
-  if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
-    # For hotspot, we need these in Windows mixed path,
-    # so rewrite them all. Need added .exe suffix.
-    HOTSPOT_CXX="$CXX.exe"
-    HOTSPOT_LD="$LD.exe"
-    HOTSPOT_MT="$MT.exe"
-    HOTSPOT_RC="$RC.exe"
-
-  unix_path="$HOTSPOT_CXX"
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-    windows_path=`$CYGPATH -m "$unix_path"`
-    HOTSPOT_CXX="$windows_path"
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-    windows_path=`cmd //c echo $unix_path`
-    HOTSPOT_CXX="$windows_path"
-  fi
-
-
-  unix_path="$HOTSPOT_LD"
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-    windows_path=`$CYGPATH -m "$unix_path"`
-    HOTSPOT_LD="$windows_path"
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-    windows_path=`cmd //c echo $unix_path`
-    HOTSPOT_LD="$windows_path"
-  fi
-
-
-  unix_path="$HOTSPOT_MT"
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-    windows_path=`$CYGPATH -m "$unix_path"`
-    HOTSPOT_MT="$windows_path"
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-    windows_path=`cmd //c echo $unix_path`
-    HOTSPOT_MT="$windows_path"
-  fi
-
-
-  unix_path="$HOTSPOT_RC"
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-    windows_path=`$CYGPATH -m "$unix_path"`
-    HOTSPOT_RC="$windows_path"
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-    windows_path=`cmd //c echo $unix_path`
-    HOTSPOT_RC="$windows_path"
-  fi
-
-
-
-  else
-    HOTSPOT_CXX="$CXX"
-    HOTSPOT_LD="$LD"
-  fi
-
-
-
-  if test  "x$TOOLCHAIN_TYPE" = xclang; then
-    USE_CLANG=true
-  fi
+  OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$CC_VERSION_NUMBER"`
+
+  fi
+
+
+
+
+
+
+
+
+
 
 
 
@@ -49914,8 +49855,8 @@
   # Need to assign to a variable since m4 is blocked from modifying parts in [].
   REFERENCE_VERSION=6
 
-  if  [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then
-    as_fn_error $? "Internal error: Cannot compare to 6, only three parts (X.Y.Z) is supported" "$LINENO" 5
+  if  [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then
+    as_fn_error $? "Internal error: Cannot compare to 6, only four parts (W.X.Y.Z) is supported" "$LINENO" 5
   fi
 
   if  [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then
@@ -49923,7 +49864,7 @@
   fi
 
   # Version comparison method inspired by http://stackoverflow.com/a/24067243
-  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"`
+  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$REFERENCE_VERSION"`
 
   if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then
     :
@@ -50214,8 +50155,8 @@
   # Need to assign to a variable since m4 is blocked from modifying parts in [].
   REFERENCE_VERSION=4.8
 
-  if  [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then
-    as_fn_error $? "Internal error: Cannot compare to 4.8, only three parts (X.Y.Z) is supported" "$LINENO" 5
+  if  [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then
+    as_fn_error $? "Internal error: Cannot compare to 4.8, only four parts (W.X.Y.Z) is supported" "$LINENO" 5
   fi
 
   if  [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then
@@ -50223,7 +50164,7 @@
   fi
 
   # Version comparison method inspired by http://stackoverflow.com/a/24067243
-  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"`
+  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$REFERENCE_VERSION"`
 
   if test $COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then
     :
@@ -50737,8 +50678,8 @@
   # Need to assign to a variable since m4 is blocked from modifying parts in [].
   REFERENCE_VERSION=6
 
-  if  [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then
-    as_fn_error $? "Internal error: Cannot compare to 6, only three parts (X.Y.Z) is supported" "$LINENO" 5
+  if  [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then
+    as_fn_error $? "Internal error: Cannot compare to 6, only four parts (W.X.Y.Z) is supported" "$LINENO" 5
   fi
 
   if  [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then
@@ -50746,7 +50687,7 @@
   fi
 
   # Version comparison method inspired by http://stackoverflow.com/a/24067243
-  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"`
+  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$REFERENCE_VERSION"`
 
   if test $OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then
     :
@@ -51037,8 +50978,8 @@
   # Need to assign to a variable since m4 is blocked from modifying parts in [].
   REFERENCE_VERSION=4.8
 
-  if  [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ; then
-    as_fn_error $? "Internal error: Cannot compare to 4.8, only three parts (X.Y.Z) is supported" "$LINENO" 5
+  if  [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ; then
+    as_fn_error $? "Internal error: Cannot compare to 4.8, only four parts (W.X.Y.Z) is supported" "$LINENO" 5
   fi
 
   if  [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ; then
@@ -51046,7 +50987,7 @@
   fi
 
   # Version comparison method inspired by http://stackoverflow.com/a/24067243
-  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", $1, $2, $3) }' <<< "$REFERENCE_VERSION"`
+  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", $1, $2, $3, $4) }' <<< "$REFERENCE_VERSION"`
 
   if test $OPENJDK_BUILD_COMPARABLE_ACTUAL_VERSION -ge $COMPARABLE_REFERENCE_VERSION ; then
     :
@@ -51917,8 +51858,8 @@
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking if native warnings are errors" >&5
 $as_echo_n "checking if native warnings are errors... " >&6; }
   if test "x$enable_warnings_as_errors" = "xyes"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (explicitely set)" >&5
-$as_echo "yes (explicitely set)" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (explicitly set)" >&5
+$as_echo "yes (explicitly set)" >&6; }
     WARNINGS_AS_ERRORS=true
   elif test "x$enable_warnings_as_errors" = "xno"; then
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
@@ -52583,28 +52524,14 @@
     COMPILE_WITH_DEBUG_SYMBOLS=true
     COPY_DEBUG_SYMBOLS=true
     ZIP_EXTERNAL_DEBUG_SYMBOLS=true
-
-    # Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true
-    DEBUG_BINARIES=false
-    STRIP_POLICY=min_strip
-
   elif test "x$NATIVE_DEBUG_SYMBOLS" = xnone; then
     COMPILE_WITH_DEBUG_SYMBOLS=false
     COPY_DEBUG_SYMBOLS=false
     ZIP_EXTERNAL_DEBUG_SYMBOLS=false
-
-    DEBUG_BINARIES=false
-    STRIP_POLICY=no_strip
   elif test "x$NATIVE_DEBUG_SYMBOLS" = xinternal; then
     COMPILE_WITH_DEBUG_SYMBOLS=true
     COPY_DEBUG_SYMBOLS=false
     ZIP_EXTERNAL_DEBUG_SYMBOLS=false
-
-    # Hotspot legacy support, will turn on -g when COPY_DEBUG_SYMBOLS=false
-    DEBUG_BINARIES=true
-    STRIP_POLICY=no_strip
-    STRIP=""
-
   elif test "x$NATIVE_DEBUG_SYMBOLS" = xexternal; then
 
     if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then
@@ -52618,10 +52545,6 @@
     COMPILE_WITH_DEBUG_SYMBOLS=true
     COPY_DEBUG_SYMBOLS=true
     ZIP_EXTERNAL_DEBUG_SYMBOLS=false
-
-    # Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true
-    DEBUG_BINARIES=false
-    STRIP_POLICY=min_strip
   else
     as_fn_error $? "Allowed native debug symbols are: none, internal, external, zipped" "$LINENO" 5
   fi
@@ -52670,10 +52593,6 @@
 
 
 
-  # Legacy values
-
-
-
 
   # Check whether --enable-native-coverage was given.
 if test "${enable_native_coverage+set}" = set; then :
@@ -53195,7 +53114,7 @@
 
 
   if test "x$with_msvcr_dll" != x; then
-    # If given explicitely by user, do not probe. If not present, fail directly.
+    # If given explicitly by user, do not probe. If not present, fail directly.
 
   DLL_NAME="$MSVCR_NAME"
   POSSIBLE_MSVC_DLL="$with_msvcr_dll"
@@ -54544,7 +54463,7 @@
 
   if test "x$MSVCP_NAME" != "x"; then
     if test "x$with_msvcp_dll" != x; then
-      # If given explicitely by user, do not probe. If not present, fail directly.
+      # If given explicitly by user, do not probe. If not present, fail directly.
 
   DLL_NAME="$MSVCP_NAME"
   POSSIBLE_MSVC_DLL="$with_msvcp_dll"
@@ -55903,7 +55822,7 @@
 
     if test "x${with_x}" != x &&  test "x${with_x}" != xyes; then
       # The user has specified a X11 base directory. Use it for includes and
-      # libraries, unless explicitely overridden.
+      # libraries, unless explicitly overridden.
       if test "x$x_includes" = xNONE; then
         x_includes="${with_x}/include"
       fi
@@ -65525,6 +65444,13 @@
   if test "x$CCACHE" != x; then
 
   if test "x$CCACHE" != x; then
+    if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then
+      HAS_BAD_CCACHE=`$ECHO $CCACHE_VERSION | \
+          $GREP -e '^1\.' -e '^2\.' -e '^3\.0\.' -e '^3\.1\.'`
+      if test "x$HAS_BAD_CCACHE" != "x"; then
+        as_fn_error $? "On macosx, ccache 3.2 or later is required, found $CCACHE_VERSION" "$LINENO" 5
+      fi
+    fi
     if test "x$USE_PRECOMPILED_HEADER" = "x1"; then
       HAS_BAD_CCACHE=`$ECHO $CCACHE_VERSION | \
           $GREP -e '^1.*' -e '^2.*' -e '^3\.0.*' -e '^3\.1\.[0123]$'`
--- a/common/autoconf/jdk-options.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/jdk-options.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -163,9 +163,9 @@
   AC_SUBST(CACERTS_FILE)
 
   # Enable or disable unlimited crypto
-  AC_ARG_ENABLE(unlimited-crypto, [AS_HELP_STRING([--enable-unlimited-crypto],
-      [Enable unlimited crypto policy @<:@disabled@:>@])],,
-      [enable_unlimited_crypto=no])
+  AC_ARG_ENABLE(unlimited-crypto, [AS_HELP_STRING([--disable-unlimited-crypto],
+      [Disable unlimited crypto policy @<:@enabled@:>@])],,
+      [enable_unlimited_crypto=yes])
   if test "x$enable_unlimited_crypto" = "xyes"; then
     UNLIMITED_CRYPTO=true
   else
@@ -265,28 +265,14 @@
     COMPILE_WITH_DEBUG_SYMBOLS=true
     COPY_DEBUG_SYMBOLS=true
     ZIP_EXTERNAL_DEBUG_SYMBOLS=true
-
-    # Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true
-    DEBUG_BINARIES=false
-    STRIP_POLICY=min_strip
-
   elif test "x$NATIVE_DEBUG_SYMBOLS" = xnone; then
     COMPILE_WITH_DEBUG_SYMBOLS=false
     COPY_DEBUG_SYMBOLS=false
     ZIP_EXTERNAL_DEBUG_SYMBOLS=false
-
-    DEBUG_BINARIES=false
-    STRIP_POLICY=no_strip
   elif test "x$NATIVE_DEBUG_SYMBOLS" = xinternal; then
     COMPILE_WITH_DEBUG_SYMBOLS=true
     COPY_DEBUG_SYMBOLS=false
     ZIP_EXTERNAL_DEBUG_SYMBOLS=false
-
-    # Hotspot legacy support, will turn on -g when COPY_DEBUG_SYMBOLS=false
-    DEBUG_BINARIES=true
-    STRIP_POLICY=no_strip
-    STRIP=""
-
   elif test "x$NATIVE_DEBUG_SYMBOLS" = xexternal; then
 
     if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then
@@ -300,10 +286,6 @@
     COMPILE_WITH_DEBUG_SYMBOLS=true
     COPY_DEBUG_SYMBOLS=true
     ZIP_EXTERNAL_DEBUG_SYMBOLS=false
-
-    # Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true
-    DEBUG_BINARIES=false
-    STRIP_POLICY=min_strip
   else
     AC_MSG_ERROR([Allowed native debug symbols are: none, internal, external, zipped])
   fi
@@ -321,10 +303,6 @@
   AC_SUBST(COMPILE_WITH_DEBUG_SYMBOLS)
   AC_SUBST(COPY_DEBUG_SYMBOLS)
   AC_SUBST(ZIP_EXTERNAL_DEBUG_SYMBOLS)
-
-  # Legacy values
-  AC_SUBST(DEBUG_BINARIES)
-  AC_SUBST(STRIP_POLICY)
 ])
 
 ################################################################################
--- a/common/autoconf/jdk-version.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/jdk-version.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -110,7 +110,7 @@
         AC_MSG_ERROR([Version string contains + but both 'BUILD' and 'OPT' are missing])
       fi
       # Stop the version part process from setting default values.
-      # We still allow them to explicitely override though.
+      # We still allow them to explicitly override though.
       NO_DEFAULT_VERSION_PARTS=true
     else
       AC_MSG_ERROR([--with-version-string fails to parse as a valid version string: $with_version_string])
--- a/common/autoconf/lib-x11.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/lib-x11.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -42,7 +42,7 @@
 
     if test "x${with_x}" != x &&  test "x${with_x}" != xyes; then
       # The user has specified a X11 base directory. Use it for includes and
-      # libraries, unless explicitely overridden.
+      # libraries, unless explicitly overridden.
       if test "x$x_includes" = xNONE; then
         x_includes="${with_x}/include"
       fi
--- a/common/autoconf/platform.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/platform.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -162,7 +162,7 @@
   # Convert the autoconf OS/CPU value to our own data, into the VAR_OS/CPU variables.
   PLATFORM_EXTRACT_VARS_FROM_OS($build_os)
   PLATFORM_EXTRACT_VARS_FROM_CPU($build_cpu)
-  # ..and setup our own variables. (Do this explicitely to facilitate searching)
+  # ..and setup our own variables. (Do this explicitly to facilitate searching)
   OPENJDK_BUILD_OS="$VAR_OS"
   if test "x$VAR_OS_TYPE" != x; then
     OPENJDK_BUILD_OS_TYPE="$VAR_OS_TYPE"
@@ -192,7 +192,7 @@
   # Convert the autoconf OS/CPU value to our own data, into the VAR_OS/CPU variables.
   PLATFORM_EXTRACT_VARS_FROM_OS($host_os)
   PLATFORM_EXTRACT_VARS_FROM_CPU($host_cpu)
-  # ... and setup our own variables. (Do this explicitely to facilitate searching)
+  # ... and setup our own variables. (Do this explicitly to facilitate searching)
   OPENJDK_TARGET_OS="$VAR_OS"
   if test "x$VAR_OS_TYPE" != x; then
     OPENJDK_TARGET_OS_TYPE="$VAR_OS_TYPE"
--- a/common/autoconf/source-dirs.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/source-dirs.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -126,6 +126,12 @@
   if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then
     IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src"
   fi
+  # Workaround for using different imported module-info.java in Jake due to a
+  # change in format. Remove once new format is standard in JDK 9 and javafx
+  # delivers just that.
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_src_jake"; then
+    IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src_jake $IMPORT_MODULES_SRC"
+  fi
   if test -d "$IMPORT_MODULES_TOPDIR/make"; then
     IMPORT_MODULES_MAKE="$IMPORT_MODULES_TOPDIR/make"
   fi
--- a/common/autoconf/toolchain.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/toolchain.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -53,7 +53,7 @@
 # Minimum supported versions, empty means unspecified
 TOOLCHAIN_MINIMUM_VERSION_clang="3.2"
 TOOLCHAIN_MINIMUM_VERSION_gcc="4.3"
-TOOLCHAIN_MINIMUM_VERSION_microsoft=""
+TOOLCHAIN_MINIMUM_VERSION_microsoft="16.00.30319.01" # VS2010
 TOOLCHAIN_MINIMUM_VERSION_solstudio="5.13"
 TOOLCHAIN_MINIMUM_VERSION_xlc=""
 
@@ -69,15 +69,15 @@
   fi
 
   # We only check CC_VERSION_NUMBER since we assume CXX_VERSION_NUMBER is equal.
-  if [ [[ "[$]$1CC_VERSION_NUMBER" =~ (.*\.){3} ]] ]; then
-    AC_MSG_WARN([C compiler version number has more than three parts (X.Y.Z): [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.])
+  if [ [[ "[$]$1CC_VERSION_NUMBER" =~ (.*\.){4} ]] ]; then
+    AC_MSG_WARN([C compiler version number has more than four parts (W.X.Y.Z): [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.])
   fi
 
   if [ [[  "[$]$1CC_VERSION_NUMBER" =~ [0-9]{6} ]] ]; then
     AC_MSG_WARN([C compiler version number has a part larger than 99999: [$]$1CC_VERSION_NUMBER. Comparisons might be wrong.])
   fi
 
-  $2COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", [$]1, [$]2, [$]3) }' <<< "[$]$1CC_VERSION_NUMBER"`
+  $2COMPARABLE_ACTUAL_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", [$]1, [$]2, [$]3, [$]4) }' <<< "[$]$1CC_VERSION_NUMBER"`
 ])
 
 # Check if the configured compiler (C and C++) is of a specific version or
@@ -94,8 +94,8 @@
   # Need to assign to a variable since m4 is blocked from modifying parts in [].
   REFERENCE_VERSION=ARG_VERSION
 
-  if [ [[ "$REFERENCE_VERSION" =~ (.*\.){3} ]] ]; then
-    AC_MSG_ERROR([Internal error: Cannot compare to ARG_VERSION, only three parts (X.Y.Z) is supported])
+  if [ [[ "$REFERENCE_VERSION" =~ (.*\.){4} ]] ]; then
+    AC_MSG_ERROR([Internal error: Cannot compare to ARG_VERSION, only four parts (W.X.Y.Z) is supported])
   fi
 
   if [ [[ "$REFERENCE_VERSION" =~ [0-9]{6} ]] ]; then
@@ -103,7 +103,7 @@
   fi
 
   # Version comparison method inspired by http://stackoverflow.com/a/24067243
-  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d\n", [$]1, [$]2, [$]3) }' <<< "$REFERENCE_VERSION"`
+  COMPARABLE_REFERENCE_VERSION=`$AWK -F. '{ printf("%05d%05d%05d%05d\n", [$]1, [$]2, [$]3, [$]4) }' <<< "$REFERENCE_VERSION"`
 
   if test [$]ARG_PREFIX[COMPARABLE_ACTUAL_VERSION] -ge $COMPARABLE_REFERENCE_VERSION ; then
     :
@@ -333,9 +333,11 @@
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     # cc -V output typically looks like
     #     cc: Sun C 5.12 Linux_i386 2011/11/16
+    # or
+    #     cc: Studio 12.5 Sun C 5.14 SunOS_sparc 2016/05/31
     COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1`
     # Check that this is likely to be the Solaris Studio cc.
-    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null
+    $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.* Sun $COMPILER_NAME" > /dev/null
     if test $? -ne 0; then
       ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1`
       AC_MSG_NOTICE([The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler.])
@@ -827,7 +829,7 @@
     BUILD_SYSROOT_CFLAGS="$SYSROOT_CFLAGS"
     BUILD_SYSROOT_LDFLAGS="$SYSROOT_LDFLAGS"
     BUILD_AR="$AR"
-    
+
     TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS([], [OPENJDK_BUILD_])
   fi
 
@@ -842,36 +844,6 @@
   AC_SUBST(BUILD_AR)
 ])
 
-# Setup legacy variables that are still needed as alternative ways to refer to
-# parts of the toolchain.
-AC_DEFUN_ONCE([TOOLCHAIN_SETUP_LEGACY],
-[
-  if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
-    # For hotspot, we need these in Windows mixed path,
-    # so rewrite them all. Need added .exe suffix.
-    HOTSPOT_CXX="$CXX.exe"
-    HOTSPOT_LD="$LD.exe"
-    HOTSPOT_MT="$MT.exe"
-    HOTSPOT_RC="$RC.exe"
-    BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(HOTSPOT_CXX)
-    BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(HOTSPOT_LD)
-    BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(HOTSPOT_MT)
-    BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH(HOTSPOT_RC)
-    AC_SUBST(HOTSPOT_MT)
-    AC_SUBST(HOTSPOT_RC)
-  else
-    HOTSPOT_CXX="$CXX"
-    HOTSPOT_LD="$LD"
-  fi
-  AC_SUBST(HOTSPOT_CXX)
-  AC_SUBST(HOTSPOT_LD)
-
-  if test  "x$TOOLCHAIN_TYPE" = xclang; then
-    USE_CLANG=true
-  fi
-  AC_SUBST(USE_CLANG)
-])
-
 # Do some additional checks on the detected tools.
 AC_DEFUN_ONCE([TOOLCHAIN_MISC_CHECKS],
 [
--- a/common/autoconf/toolchain_windows.m4	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/autoconf/toolchain_windows.m4	Wed Jul 05 22:32:06 2017 +0200
@@ -566,7 +566,7 @@
       [path to microsoft C runtime dll (msvcr*.dll) (Windows only) @<:@probed@:>@])])
 
   if test "x$with_msvcr_dll" != x; then
-    # If given explicitely by user, do not probe. If not present, fail directly.
+    # If given explicitly by user, do not probe. If not present, fail directly.
     TOOLCHAIN_CHECK_POSSIBLE_MSVC_DLL($MSVCR_NAME, [$with_msvcr_dll], [--with-msvcr-dll])
     if test "x$MSVC_DLL" = x; then
       AC_MSG_ERROR([Could not find a proper $MSVCR_NAME as specified by --with-msvcr-dll])
@@ -589,7 +589,7 @@
 
   if test "x$MSVCP_NAME" != "x"; then
     if test "x$with_msvcp_dll" != x; then
-      # If given explicitely by user, do not probe. If not present, fail directly.
+      # If given explicitly by user, do not probe. If not present, fail directly.
       TOOLCHAIN_CHECK_POSSIBLE_MSVC_DLL($MSVCP_NAME, [$with_msvcp_dll], [--with-msvcp-dll])
       if test "x$MSVC_DLL" = x; then
         AC_MSG_ERROR([Could not find a proper $MSVCP_NAME as specified by --with-msvcp-dll])
--- a/common/bin/compare.sh	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/bin/compare.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -1295,8 +1295,8 @@
         OTHER_JDK="$OTHER/images/jdk"
         OTHER_JRE="$OTHER/images/jre"
         echo "Selecting jdk images for compare"
-    elif [ -d "$(ls -d $THIS/licensee-src/build/*/images/jdk)" ] \
-        && [ -d "$(ls -d $OTHER/licensee-src/build/*/images/jdk)" ]
+    elif [ -d "$(ls -d $THIS/licensee-src/build/*/images/jdk 2> /dev/null)" ] \
+        && [ -d "$(ls -d $OTHER/licensee-src/build/*/images/jdk 2> /dev/null)" ]
     then
         echo "Selecting licensee images for compare"
         # Simply override the THIS and OTHER dir with the build dir from
--- a/common/conf/jib-profiles.js	Fri Dec 02 10:52:51 2016 -0800
+++ b/common/conf/jib-profiles.js	Wed Jul 05 22:32:06 2017 +0200
@@ -427,7 +427,7 @@
         jtreg: {
             server: "javare",
             revision: "4.2",
-            build_number: "b03",
+            build_number: "b04",
             checksum_file: "MD5_VALUES",
             file: "jtreg_bin-4.2.zip",
             environment_name: "JT_HOME",
--- a/corba/.hgignore	Fri Dec 02 10:52:51 2016 -0800
+++ b/corba/.hgignore	Wed Jul 05 22:32:06 2017 +0200
@@ -2,5 +2,4 @@
 ^dist/
 ^webrev
 /nbproject/private/
-^.hgtip
 .DS_Store
--- a/corba/.hgtags	Fri Dec 02 10:52:51 2016 -0800
+++ b/corba/.hgtags	Wed Jul 05 22:32:06 2017 +0200
@@ -389,3 +389,4 @@
 d4f1dae174098e799c48948e866054c52e11a186 jdk-9+144
 a44b156ae7f06bf41b9bece30df7775e482395dd jdk-9+145
 ecd74b41ab65bf228837b5bdf99690638d55425c jdk-9+146
+dc49e0922a8e4387cbf8670bbe1dc51c9874b74b jdk-9+147
--- a/corba/src/java.corba/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/corba/src/java.corba/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,10 @@
 /**
  * Defines the Java binding of the OMG CORBA APIs, and the RMI-IIOP API.
  */
+@Deprecated(since="9", forRemoval=true)
 module java.corba {
-    requires public java.desktop;
-    requires public java.rmi;
+    requires transitive java.desktop;
+    requires transitive java.rmi;
     requires java.logging;
     requires java.naming;
     requires java.transaction;
@@ -65,14 +66,13 @@
     exports org.omg.PortableServer.portable;
     exports org.omg.SendingContext;
     exports org.omg.stub.java.rmi;
-    exports com.sun.corba.se.impl.util to
-        jdk.rmic;
-    exports com.sun.jndi.cosnaming to
-        java.naming;
-    exports com.sun.jndi.url.corbaname to
-        java.naming;
-    exports com.sun.jndi.url.iiop to
-        java.naming;
-    exports com.sun.jndi.url.iiopname to
-        java.naming;
+
+    // rmic --iiop
+    exports com.sun.corba.se.impl.util to jdk.rmic;
+
+    // JNDI CosNaming provider
+    opens com.sun.jndi.cosnaming to java.naming;  // jndiprovider.properties
+    exports com.sun.jndi.url.corbaname to java.naming;
+    exports com.sun.jndi.url.iiop to java.naming;
+    exports com.sun.jndi.url.iiopname to java.naming;
 }
--- a/hotspot/.hgignore	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/.hgignore	Wed Jul 05 22:32:06 2017 +0200
@@ -8,7 +8,6 @@
 ^src/share/tools/IdealGraphVisualizer/dist/
 ^src/share/tools/IdealGraphVisualizer/nbplatform/
 .igv.log
-^.hgtip
 .DS_Store
 ^\.mx.jvmci/env
 ^\.mx.jvmci/.*\.pyc
--- a/hotspot/.hgtags	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/.hgtags	Wed Jul 05 22:32:06 2017 +0200
@@ -549,3 +549,4 @@
 6187b582d02aee38341dc8ce4011906e9b364e9f jdk-9+144
 61e7ea56312351657e69198c503a6f7bf865af83 jdk-9+145
 a82cb5350cad96a0b4de496afebe3ded89f27efa jdk-9+146
+132a72c782071cc11ab25cc7c9ee167c3632fea4 jdk-9+147
--- a/hotspot/make/symbols/symbols-unix	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/make/symbols/symbols-unix	Wed Jul 05 22:32:06 2017 +0200
@@ -190,8 +190,6 @@
 JVM_AddModuleExportsToAllUnnamed
 JVM_AddModulePackage
 JVM_AddReadsModule
-JVM_CanReadModule
 JVM_DefineModule
-JVM_IsExportedToModule
 JVM_SetBootLoaderUnnamedModule
 JVM_GetModuleByPackageName
--- a/hotspot/make/test/JtregNative.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/make/test/JtregNative.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -55,6 +55,9 @@
     $(HOTSPOT_TOPDIR)/test/compiler/calls \
     $(HOTSPOT_TOPDIR)/test/compiler/native \
     $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
+    $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleReads \
+    $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleExportsAndOpens \
+    $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleUsesAndProvides \
     $(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \
     $(HOTSPOT_TOPDIR)/test/compiler/jvmci/jdk.vm.ci.code.test \
     $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetModulesInfo \
@@ -81,6 +84,9 @@
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_liboverflow := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libSimpleClassFileLoadHook := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libGetNamedModuleTest := -lc
+    BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libAddModuleReadsTest := -lc
+    BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libAddModuleExportsAndOpensTest := -lc
+    BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libAddModuleUsesAndProvidesTest := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAClassFileLoadHook := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAClassLoadPrepare := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAThreadStart := -lc
--- a/hotspot/src/jdk.vm.ci/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/jdk.vm.ci/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,9 +30,7 @@
     uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory;
 
     provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with
-        jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory;
-    provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with
-        jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory;
-    provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with
+        jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory,
+        jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory,
         jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory;
 }
--- a/hotspot/src/share/vm/classfile/moduleEntry.hpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp	Wed Jul 05 22:32:06 2017 +0200
@@ -36,6 +36,8 @@
 #include "utilities/ostream.hpp"
 
 #define UNNAMED_MODULE "Unnamed Module"
+#define JAVAPKG "java/"
+#define JAVAPKG_LEN 5
 
 class ModuleClosure;
 
--- a/hotspot/src/share/vm/classfile/modules.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/classfile/modules.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -34,6 +34,7 @@
 #include "classfile/packageEntry.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "logging/log.hpp"
 #include "memory/resourceArea.hpp"
@@ -44,6 +45,7 @@
 #include "runtime/handles.inline.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/reflection.hpp"
+#include "utilities/stringUtils.hpp"
 #include "utilities/utf8.hpp"
 
 static bool verify_module_name(char *module_name) {
@@ -290,6 +292,14 @@
 
   const char* module_version = get_module_version(version);
 
+  oop loader = java_lang_reflect_Module::loader(module_handle());
+  // Make sure loader is not the jdk.internal.reflect.DelegatingClassLoader.
+  if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "Class loader is an invalid delegating class loader");
+  }
+  Handle h_loader = Handle(THREAD, loader);
+
   objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages));
   objArrayHandle packages_h(THREAD, packages_oop);
   int num_packages = (packages_h == NULL ? 0 : packages_h->length());
@@ -310,6 +320,21 @@
                 err_msg("Invalid package name: %s for module: %s",
                         package_name, module_name));
     }
+
+    // Only modules defined to either the boot or platform class loader, can define a "java/" package.
+    if (!h_loader.is_null() &&
+        !SystemDictionary::is_platform_class_loader(h_loader) &&
+        strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) {
+      const char* class_loader_name = SystemDictionary::loader_name(h_loader());
+      StringUtils::replace_no_expand(package_name, "/", ".");
+      const char* msg_text1 = "Class loader (instance of): ";
+      const char* msg_text2 = " tried to define prohibited package name: ";
+      size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1;
+      char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len);
+      jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name);
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
+    }
+
     Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
     // append_if_missing() returns FALSE if entry already exists.
     if (!pkg_list->append_if_missing(pkg_symbol)) {
@@ -319,20 +344,6 @@
     }
   }
 
-  oop loader = java_lang_reflect_Module::loader(module_handle());
-  // Make sure loader is not the sun.reflect.DelegatingClassLoader.
-  if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) {
-    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-              "Class loader is an invalid delegating class loader");
-  }
-  Handle h_loader = Handle(THREAD, loader);
-
-  // Check that loader is a subclass of java.lang.ClassLoader.
-  if (loader != NULL && !java_lang_ClassLoader::is_subclass(h_loader->klass())) {
-    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
-              "Class loader is not a subclass of java.lang.ClassLoader");
-  }
-
   ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK);
   assert(module_table != NULL, "module entry table shouldn't be null");
 
@@ -595,122 +606,6 @@
   }
 }
 
-jboolean Modules::can_read_module(jobject asking_module, jobject target_module, TRAPS) {
-  if (asking_module == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
-               "asking_module is null", JNI_FALSE);
-  }
-
-  ModuleEntry* asking_module_entry = get_module_entry(asking_module, CHECK_false);
-  if (asking_module_entry == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
-               "asking_module is invalid", JNI_FALSE);
-  }
-
-  // Calling can_read_all_unnamed() with NULL tests if a module is loose.
-  if (target_module == NULL) {
-    return asking_module_entry->can_read_all_unnamed();
-  }
-
-  ModuleEntry* target_module_entry = get_module_entry(target_module, CHECK_false);
-  if (target_module_entry == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
-               "target_module is invalid", JNI_FALSE);
-  }
-
-  ResourceMark rm(THREAD);
-  log_debug(modules)("can_read_module(): module %s trying to read module %s, allowed = %s",
-                     asking_module_entry->is_named() ?
-                       asking_module_entry->name()->as_C_string() : UNNAMED_MODULE,
-                     target_module_entry->is_named() ?
-                       target_module_entry->name()->as_C_string() : UNNAMED_MODULE,
-                     BOOL_TO_STR(asking_module_entry == target_module_entry ||
-                                 (asking_module_entry->can_read_all_unnamed() &&
-                                  !target_module_entry->is_named()) ||
-                                  asking_module_entry->can_read(target_module_entry)));
-
-  // Return true if:
-  // 1. the modules are the same, or
-  // 2. the asking_module is unnamed (because unnamed modules read everybody), or
-  // 3. the asking_module is loose and the target module is unnamed, or
-  // 4. if can_read() returns true.
-  if (asking_module_entry == target_module_entry ||
-      (asking_module_entry->can_read_all_unnamed() && !target_module_entry->is_named())) {
-    return true;
-  }
-  return asking_module_entry->can_read(target_module_entry);
-}
-
-jboolean Modules::is_exported_to_module(jobject from_module, jstring package,
-                                        jobject to_module, TRAPS) {
-  if (package == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
-               "package is null", JNI_FALSE);
-  }
-  if (from_module == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
-               "from_module is null", JNI_FALSE);
-  }
-  ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK_false);
-  if (from_module_entry == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
-               "from_module is invalid", JNI_FALSE);
-  }
-  ModuleEntry* to_module_entry;
-  if (to_module == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
-               "to_module is null", JNI_FALSE);
-  }
-  to_module_entry = get_module_entry(to_module, CHECK_false);
-  if (to_module_entry == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
-               "to_module is invalid", JNI_FALSE);
-  }
-
-  PackageEntry *package_entry = get_package_entry(from_module_entry, package,
-                                                  CHECK_false);
-  ResourceMark rm(THREAD);
-  if (package_entry == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
-               err_msg("Package not found in from_module: %s",
-                       from_module_entry->is_named() ?
-                         from_module_entry->name()->as_C_string() : UNNAMED_MODULE),
-               JNI_FALSE);
-  }
-  if (package_entry->module() != from_module_entry) {
-    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
-               err_msg("Package: %s found in module %s, not in from_module: %s",
-                       package_entry->name()->as_C_string(),
-                       package_entry->module()->is_named() ?
-                         package_entry->module()->name()->as_C_string() : UNNAMED_MODULE,
-                       from_module_entry->is_named() ?
-                         from_module_entry->name()->as_C_string() : UNNAMED_MODULE),
-               JNI_FALSE);
-  }
-
-  log_debug(modules)("is_exported_to_module: package %s from module %s checking"
-                     " if exported to module %s, exported? = %s",
-                     package_entry->name()->as_C_string(),
-                     from_module_entry->is_named() ?
-                       from_module_entry->name()->as_C_string() : UNNAMED_MODULE,
-                     to_module_entry->is_named() ?
-                       to_module_entry->name()->as_C_string() : UNNAMED_MODULE,
-                     BOOL_TO_STR(!from_module_entry->is_named() ||
-                       package_entry->is_unqual_exported() ||
-                       from_module_entry == to_module_entry ||
-                       package_entry->is_qexported_to(to_module_entry)));
-
-  // Return true if:
-  // 1. from_module is unnamed because unnamed modules export all their packages (by default), or
-  // 2. if the package is unqualifiedly exported, or
-  // 3. if the modules are the same, or
-  // 4. if the package is exported to to_module
-  return (!from_module_entry->is_named() ||
-          package_entry->is_unqual_exported() ||
-          from_module_entry == to_module_entry ||
-          package_entry->is_qexported_to(to_module_entry));
-}
-
 // This method is called by JFR and JNI.
 jobject Modules::get_module(jclass clazz, TRAPS) {
   assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_module before java.base is defined");
@@ -860,11 +755,27 @@
               err_msg("Invalid package name: %s", package_name));
   }
 
+  ClassLoaderData *loader_data = module_entry->loader_data();
+
+  // Only modules defined to either the boot or platform class loader, can define a "java/" package.
+  if (!loader_data->is_the_null_class_loader_data() &&
+      !loader_data->is_platform_class_loader_data() &&
+      strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) {
+    const char* class_loader_name = SystemDictionary::loader_name(loader_data);
+    StringUtils::replace_no_expand(package_name, "/", ".");
+    const char* msg_text1 = "Class loader (instance of): ";
+    const char* msg_text2 = " tried to define prohibited package name: ";
+    size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1;
+    char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len);
+    jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name);
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
+  }
+
   log_debug(modules)("add_module_package(): Adding package %s to module %s",
                      package_name, module_entry->name()->as_C_string());
 
   TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
-  PackageEntryTable* package_table = module_entry->loader_data()->packages();
+  PackageEntryTable* package_table = loader_data->packages();
   assert(package_table != NULL, "Missing package_table");
 
   bool pkg_exists = false;
--- a/hotspot/src/share/vm/classfile/modules.hpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/classfile/modules.hpp	Wed Jul 05 22:32:06 2017 +0200
@@ -93,24 +93,6 @@
   // module does not exist.
   static void add_reads_module(jobject from_module, jobject to_module, TRAPS);
 
-  // can_read_module returns TRUE if module asking_module can read module target_module,
-  // or if they are the same module, or if the asking_module is loose and target_module
-  // is null.
-  //
-  // Throws IllegalArgumentException if:
-  // * either asking_module or target_module is not a java.lang.reflect.Module
-  static jboolean can_read_module(jobject asking_module, jobject target_module, TRAPS);
-
-  // If package is valid then this returns TRUE if module from_module exports
-  // package to module to_module, if from_module and to_module are the same
-  // module, or if package is exported without qualification.
-  //
-  // IllegalArgumentException is throw if:
-  // * Either to_module or from_module does not exist
-  // * package is syntactically incorrect
-  // * package is not in from_module
-  static jboolean is_exported_to_module(jobject from_module, jstring package, jobject to_module, TRAPS);
-
   // Return the java.lang.reflect.Module object for this class object.
   static jobject get_module(jclass clazz, TRAPS);
 
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed Jul 05 22:32:06 2017 +0200
@@ -451,8 +451,6 @@
   template(loader_name,                               "loader")                                   \
   template(module_name,                               "module")                                   \
   template(getModule_name,                            "getModule")                                \
-  template(addReads_name,                             "addReads")                                 \
-  template(addReads_signature,                        "(Ljava/lang/reflect/Module;Ljava/lang/reflect/Module;)V")           \
   template(input_stream_void_signature,               "(Ljava/io/InputStream;)V")                 \
   template(definePackage_name,                        "definePackage")                            \
   template(definePackage_signature,                   "(Ljava/lang/String;Ljava/lang/reflect/Module;)Ljava/lang/Package;") \
@@ -645,6 +643,15 @@
   /* JVMTI/java.lang.instrument support and VM Attach mechanism */                                                \
   template(jdk_internal_module_Modules,                "jdk/internal/module/Modules")                             \
   template(jdk_internal_vm_VMSupport,                  "jdk/internal/vm/VMSupport")                               \
+  template(addReads_name,                              "addReads")                                                \
+  template(addReads_signature,                         "(Ljava/lang/reflect/Module;Ljava/lang/reflect/Module;)V") \
+  template(addExports_name,                            "addExports")                                              \
+  template(addOpens_name,                              "addOpens")                                                \
+  template(addExports_signature,                       "(Ljava/lang/reflect/Module;Ljava/lang/String;Ljava/lang/reflect/Module;)V") \
+  template(addUses_name,                               "addUses")                                                 \
+  template(addUses_signature,                          "(Ljava/lang/reflect/Module;Ljava/lang/Class;)V")          \
+  template(addProvides_name,                           "addProvides")                                             \
+  template(addProvides_signature,                      "(Ljava/lang/reflect/Module;Ljava/lang/Class;Ljava/lang/Class;)V") \
   template(transformedByAgent_name,                    "transformedByAgent")                                      \
   template(transformedByAgent_signature,               "(Ljava/lang/reflect/Module;)V")                           \
   template(appendToClassPathForInstrumentation_name,   "appendToClassPathForInstrumentation")                     \
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
 #include "classfile/javaClasses.hpp"
+#include "classfile/moduleEntry.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "classfile/verifier.hpp"
@@ -2383,18 +2384,17 @@
 
 // Only boot and platform class loaders can define classes in "java/" packages.
 void InstanceKlass::check_prohibited_package(Symbol* class_name,
-                                                Handle class_loader,
-                                                TRAPS) {
-  const char* javapkg = "java/";
+                                             Handle class_loader,
+                                             TRAPS) {
   ResourceMark rm(THREAD);
   if (!class_loader.is_null() &&
       !SystemDictionary::is_platform_class_loader(class_loader) &&
       class_name != NULL &&
-      strncmp(class_name->as_C_string(), javapkg, strlen(javapkg)) == 0) {
+      strncmp(class_name->as_C_string(), JAVAPKG, JAVAPKG_LEN) == 0) {
     TempNewSymbol pkg_name = InstanceKlass::package_from_name(class_name, CHECK);
     assert(pkg_name != NULL, "Error in parsing package name starting with 'java/'");
     char* name = pkg_name->as_C_string();
-    const char* class_loader_name = InstanceKlass::cast(class_loader()->klass())->name()->as_C_string();
+    const char* class_loader_name = SystemDictionary::loader_name(class_loader());
     StringUtils::replace_no_expand(name, "/", ".");
     const char* msg_text1 = "Class loader (instance of): ";
     const char* msg_text2 = " tried to load prohibited package name: ";
--- a/hotspot/src/share/vm/prims/jni.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jni.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -3475,40 +3475,6 @@
 JNI_END
 
 
-JNI_ENTRY(void, jni_AddModuleReads(JNIEnv* env, jobject m1, jobject m2))
-  JNIWrapper("AddModuleReads");
-  if (m1 == NULL || m2 == NULL) {
-    THROW(vmSymbols::java_lang_NullPointerException());
-  }
-  JavaValue result(T_VOID);
-  Handle m1_h(THREAD, JNIHandles::resolve(m1));
-  if (!java_lang_reflect_Module::is_instance(m1_h())) {
-    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad m1 object");
-  }
-  Handle m2_h(THREAD, JNIHandles::resolve(m2));
-  if (!java_lang_reflect_Module::is_instance(m2_h())) {
-    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad m2 object");
-  }
-  JavaCalls::call_static(&result,
-                         KlassHandle(THREAD, SystemDictionary::module_Modules_klass()),
-                         vmSymbols::addReads_name(),
-                         vmSymbols::addReads_signature(),
-                         m1_h,
-                         m2_h,
-                         THREAD);
-JNI_END
-
-
-JNI_ENTRY(jboolean, jni_CanReadModule(JNIEnv* env, jobject m1, jobject m2))
-  JNIWrapper("CanReadModule");
-  if (m1 == NULL || m2 == NULL) {
-    THROW_(vmSymbols::java_lang_NullPointerException(), JNI_FALSE);
-  }
-  jboolean res = Modules::can_read_module(m1, m2, CHECK_false);
-  return res;
-JNI_END
-
-
 // Structure containing all jni functions
 struct JNINativeInterface_ jni_NativeInterface = {
     NULL,
@@ -3792,9 +3758,7 @@
 
     // Module features
 
-    jni_GetModule,
-    jni_AddModuleReads,
-    jni_CanReadModule
+    jni_GetModule
 };
 
 
--- a/hotspot/src/share/vm/prims/jni.h	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jni.h	Wed Jul 05 22:32:06 2017 +0200
@@ -770,12 +770,6 @@
 
     jobject (JNICALL *GetModule)
        (JNIEnv* env, jclass clazz);
-
-    void (JNICALL *AddModuleReads)
-       (JNIEnv* env, jobject m1, jobject m2);
-
-    jboolean (JNICALL *CanReadModule)
-       (JNIEnv* env, jobject m1, jobject m2);
 };
 
 /*
@@ -1874,14 +1868,6 @@
         return functions->GetModule(this, clazz);
     }
 
-    void AddModuleReads(jobject fromModule, jobject sourceModule) {
-        functions->AddModuleReads(this, fromModule, sourceModule);
-    }
-
-    jboolean CanReadModule(jobject askingModule, jobject sourceModule) {
-        return functions->CanReadModule(this, askingModule, sourceModule);
-    }
-
 #endif /* __cplusplus */
 };
 
--- a/hotspot/src/share/vm/prims/jniCheck.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jniCheck.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -2001,37 +2001,6 @@
     return result;
 JNI_END
 
-JNI_ENTRY_CHECKED(void,
-  checked_jni_AddModuleReads(JNIEnv *env,
-                             jobject fromModule,
-                             jobject sourceModule))
-    functionEnter(thr);
-    IN_VM(
-      jniCheck::validate_object(thr, fromModule);
-      if (sourceModule != NULL) {
-        jniCheck::validate_object(thr, sourceModule);
-      }
-    )
-    UNCHECKED()->AddModuleReads(env,fromModule,sourceModule);
-    functionExit(thr);
-JNI_END
-
-JNI_ENTRY_CHECKED(jboolean,
-  checked_jni_CanReadModule(JNIEnv *env,
-                            jobject askingModule,
-                            jobject sourceModule))
-    functionEnter(thr);
-    IN_VM(
-      jniCheck::validate_object(thr, askingModule);
-      if (sourceModule != NULL) {
-        jniCheck::validate_object(thr, sourceModule);
-      }
-    )
-    jboolean result = UNCHECKED()->CanReadModule(env,askingModule,sourceModule);
-    functionExit(thr);
-    return result;
-JNI_END
-
 /*
  * Structure containing all checked jni functions
  */
@@ -2317,9 +2286,7 @@
 
     // Module Features
 
-    checked_jni_GetModule,
-    checked_jni_AddModuleReads,
-    checked_jni_CanReadModule
+    checked_jni_GetModule
 };
 
 
--- a/hotspot/src/share/vm/prims/jvm.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jvm.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -1008,8 +1008,8 @@
 
 // Module support //////////////////////////////////////////////////////////////////////////////
 
-JVM_ENTRY(void, JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location,
-                                 jobjectArray packages))
+JVM_ENTRY(void, JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version,
+                                 jstring location, jobjectArray packages))
   JVMWrapper("JVM_DefineModule");
   Modules::define_module(module, version, location, packages, CHECK);
 JVM_END
@@ -1039,16 +1039,6 @@
   Modules::add_reads_module(from_module, source_module, CHECK);
 JVM_END
 
-JVM_ENTRY(jboolean, JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module))
-  JVMWrapper("JVM_CanReadModule");
-  return Modules::can_read_module(asking_module, source_module, THREAD);
-JVM_END
-
-JVM_ENTRY(jboolean, JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module))
-  JVMWrapper("JVM_IsExportedToModule");
-  return Modules::is_exported_to_module(from_module, package, to_module, THREAD);
-JVM_END
-
 JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, jstring package))
   JVMWrapper("JVM_AddModulePackage");
   Modules::add_module_package(module, package, CHECK);
--- a/hotspot/src/share/vm/prims/jvm.h	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jvm.h	Wed Jul 05 22:32:06 2017 +0200
@@ -413,8 +413,8 @@
  */
 
 JNIEXPORT void JNICALL
-JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location,
-                 jobjectArray packages);
+JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version,
+                 jstring location, jobjectArray packages);
 
 JNIEXPORT void JNICALL
 JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module);
@@ -431,12 +431,6 @@
 JNIEXPORT void JNICALL
 JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module);
 
-JNIEXPORT jboolean JNICALL
-JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module);
-
-JNIEXPORT jboolean JNICALL
-JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module);
-
 JNIEXPORT void JNICALL
 JVM_AddModulePackage(JNIEnv* env,  jobject module, jstring package);
 
--- a/hotspot/src/share/vm/prims/jvmti.xml	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jvmti.xml	Wed Jul 05 22:32:06 2017 +0200
@@ -863,14 +863,12 @@
   </intro>
 
 <intro id="bcimodules" label="Bytecode Instrumentation of code in modules">
-  Agents that instrument code in named modules may need to arrange for those
-  modules to read other modules. If code is instrumented to invoke a method
-  in a support class in another module, then the module of the instrumented
-  code should read the module of the supporting class. Furthermore, the
-  supporting class will only be accessible to the instrumented code if
-  it is <code>public</code> and in a package that is exported by its module.
-  Agents can use the JNI functions <code>CanReadModule</code> and
-  <code>AddModuleReads</code> to test and update a module to read another.
+  Agents can use the functions <functionlink id="AddModuleReads"/>,
+  <functionlink id="AddModuleExports"/>, <functionlink id="AddModuleOpens"/>,
+  <functionlink id="AddModuleUses"/> and <functionlink id="AddModuleProvides"/>
+  to update a module to expand the set of modules that it reads, the set of
+  packages that it exports or opens to other modules, or the services that it
+  uses and provides.
   <p/>
   As an aid to agents that deploy supporting classes on the search path of
   the bootstrap class loader, or the search path of the class loader that
@@ -6561,6 +6559,227 @@
         </error>
       </errors>
     </function>
+
+    <function id="AddModuleReads" num="94" since="9">
+      <synopsis>Add Module Reads</synopsis>
+      <description>
+         Update a module to read another module. This function is a no-op
+         when <paramlink id="module"></paramlink> is an unnamed module.
+         This function facilitates the instrumentation of code
+         in named modules where that instrumentation requires
+         expanding the set of modules that a module reads.
+      </description>
+      <origin>new</origin>
+      <capabilities>
+      </capabilities>
+      <parameters>
+        <param id="module">
+          <ptrtype><jobject/></ptrtype>
+          <description>
+            The module to update.
+          </description>
+        </param>
+        <param id="to_module">
+          <ptrtype><jobject/></ptrtype>
+          <description>
+            The additional module to read.
+          </description>
+        </param>
+      </parameters>
+      <errors>
+        <error id="JVMTI_ERROR_INVALID_MODULE">
+          If <paramlink id="module"></paramlink> is not a module object.
+        </error>
+        <error id="JVMTI_ERROR_INVALID_MODULE">
+          If <paramlink id="to_module"></paramlink> is not a module object.
+        </error>
+      </errors>
+    </function>
+
+    <function id="AddModuleExports" num="95" since="9">
+      <synopsis>Add Module Exports</synopsis>
+      <description>
+         Update a module to export a package to another module.
+         This function is a no-op when <paramlink id="module"></paramlink>
+         is an unnamed module or an open module.
+         This function facilitates the instrumentation of code
+         in named modules where that instrumentation requires
+         expanding the set of packages that a module exports.
+      </description>
+      <origin>new</origin>
+      <capabilities>
+      </capabilities>
+      <parameters>
+        <param id="module">
+          <ptrtype><jobject/></ptrtype>
+          <description>
+            The module to update.
+          </description>
+        </param>
+        <param id="pkg_name">
+          <inbuf><char/></inbuf>
+          <description>
+            The exported package name.
+          </description>
+        </param>
+        <param id="to_module">
+          <ptrtype><jobject/></ptrtype>
+          <description>
+            The module the package is exported to.
+            If the <code>to_module</code> is not a subclass of
+            <code>java.lang.reflect.Module</code> this function returns
+            <errorlink id="JVMTI_ERROR_INVALID_MODULE"></errorlink>.
+          </description>
+        </param>
+      </parameters>
+      <errors>
+        <error id="JVMTI_ERROR_INVALID_MODULE">
+          If <paramlink id="module"></paramlink> is not a module object.
+        </error>
+        <error id="JVMTI_ERROR_INVALID_MODULE">
+          If <paramlink id="to_modules"></paramlink> is not a module object.
+        </error>
+        <error id="JVMTI_ERROR_ILLEGAL_ARGUMENT">
+          If the package <paramlink id="pkg_name"></paramlink>
+          does not belong to the module.
+        </error>
+      </errors>
+    </function>
+
+    <function id="AddModuleOpens" num="96" since="9">
+      <synopsis>Add Module Opens</synopsis>
+      <description>
+         Update a module to open a package to another module.
+         This function is a no-op when <paramlink id="module"></paramlink>
+         is an unnamed module or an open module.
+         This function facilitates the instrumentation of code
+         in modules where that instrumentation requires
+         expanding the set of packages that a module opens to
+         other modules.
+      </description>
+      <origin>new</origin>
+      <capabilities>
+      </capabilities>
+      <parameters>
+        <param id="module">
+          <ptrtype><jobject/></ptrtype>
+          <description>
+            The module to update.
+          </description>
+        </param>
+        <param id="pkg_name">
+          <inbuf><char/></inbuf>
+          <description>
+            The package name of the package to open.
+          </description>
+        </param>
+        <param id="to_module">
+          <ptrtype><jobject/></ptrtype>
+          <description>
+            The module with the package to open.
+            If the <code>to_module</code> is not a subclass of
+            <code>java.lang.reflect.Module</code> this function returns
+            <errorlink id="JVMTI_ERROR_INVALID_MODULE"></errorlink>.
+          </description>
+        </param>
+      </parameters>
+      <errors>
+        <error id="JVMTI_ERROR_INVALID_MODULE">
+          If <paramlink id="module"></paramlink> is not a module object.
+        </error>
+        <error id="JVMTI_ERROR_INVALID_MODULE">
+          If <paramlink id="to_modules"></paramlink> is not a module object.
+        </error>
+        <error id="JVMTI_ERROR_ILLEGAL_ARGUMENT">
+          If the package <paramlink id="pkg_name"></paramlink>
+          does not belong to the module.
+        </error>
+      </errors>
+    </function>
+
+    <function id="AddModuleUses" num="97" since="9">
+      <synopsis>Add Module Uses</synopsis>
+      <description>
+         Updates a module to add a service to the set of services that
+         a module uses. This function is a no-op when the module
+         is an unnamed module.
+         This function facilitates the instrumentation of code
+         in named modules where that instrumentation requires
+         expanding the set of services that a module is using.
+      </description>
+      <origin>new</origin>
+      <capabilities>
+      </capabilities>
+      <parameters>
+        <param id="module">
+          <ptrtype><jobject/></ptrtype>
+          <description>
+            The module to update.
+          </description>
+        </param>
+        <param id="service">
+          <ptrtype><jclass/></ptrtype>
+          <description>
+            The service to use.
+          </description>
+        </param>
+      </parameters>
+      <errors>
+        <error id="JVMTI_ERROR_INVALID_MODULE">
+          If <paramlink id="module"></paramlink> is not a module object.
+        </error>
+        <error id="JVMTI_ERROR_INVALID_CLASS">
+          If <paramlink id="service"></paramlink> is not a class object.
+        </error>
+      </errors>
+    </function>
+
+    <function id="AddModuleProvides" num="98" since="9">
+      <synopsis>Add Module Provides</synopsis>
+      <description>
+         Updates a module to add a service to the set of services that
+         a module provides. This function is a no-op when the module
+         is an unnamed module.
+         This function facilitates the instrumentation of code
+         in named modules where that instrumentation requires
+         changes to the services that are provided.
+      </description>
+      <origin>new</origin>
+      <capabilities>
+      </capabilities>
+      <parameters>
+        <param id="module">
+          <ptrtype><jobject/></ptrtype>
+          <description>
+            The module to update.
+          </description>
+        </param>
+        <param id="service">
+          <ptrtype><jclass/></ptrtype>
+          <description>
+            The service to provide.
+          </description>
+        </param>
+        <param id="impl_class">
+          <ptrtype><jclass/></ptrtype>
+          <description>
+            The implementation class for the provided service.
+          </description>
+        </param>
+      </parameters>
+      <errors>
+        <error id="JVMTI_ERROR_INVALID_MODULE">
+          If <paramlink id="module"></paramlink> is not a module object.
+        </error>
+        <error id="JVMTI_ERROR_INVALID_CLASS">
+          If <paramlink id="service"></paramlink> is not a class object.
+        </error>
+        <error id="JVMTI_ERROR_INVALID_CLASS">
+          If <paramlink id="impl_class"></paramlink> is not a class object.
+        </error>
+      </errors>
+    </function>
+
   </category>
 
   <category id="class" label="Class">
@@ -11371,6 +11590,9 @@
     <errorid id="JVMTI_ERROR_INVALID_FIELDID" num="25">
       Invalid field.
     </errorid>
+    <errorid id="JVMTI_ERROR_INVALID_MODULE" num="26">
+      Invalid module.
+    </errorid>
     <errorid id="JVMTI_ERROR_INVALID_METHODID" num="23">
       Invalid method.
     </errorid>
@@ -14492,17 +14714,17 @@
   <change date="19 June 2013" version="1.2.3">
       Added support for statically linked agents.
   </change>
-  <change date="5 July 2016" version="9.0.0">
+  <change date="13 October 2016" version="9.0.0">
       Support for modules:
        - The majorversion is 9 now
        - The ClassFileLoadHook events are not sent during the primordial phase anymore.
-       - Add new function GetAllModules
-       - Add new capability can_generate_early_vmstart
        - Allow CompiledMethodLoad events at start phase
-       - Add new capability can_generate_early_class_hook_events
-       - Add new function GetNamedModule
-  </change>
-  <change date="16 August 2016" version="9.0.0">
+       - Add new capabilities:
+          - can_generate_early_vmstart
+          - can_generate_early_class_hook_events
+       - Add new functions:
+          - GetAllModules
+          - AddModuleReads, AddModuleExports, AddModuleOpens, AddModuleUses, AddModuleProvides
       Clarified can_redefine_any_classes, can_retransform_any_classes and IsModifiableClass API to
       disallow some implementation defined classes.
   </change>
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -227,6 +227,119 @@
 } /* end GetNamedModule */
 
 
+// module - pre-checked for NULL
+// to_module - pre-checked for NULL
+jvmtiError
+JvmtiEnv::AddModuleReads(jobject module, jobject to_module) {
+  JavaThread* THREAD = JavaThread::current();
+
+  // check module
+  Handle h_module(THREAD, JNIHandles::resolve(module));
+  if (!java_lang_reflect_Module::is_instance(h_module())) {
+    return JVMTI_ERROR_INVALID_MODULE;
+  }
+  // check to_module
+  Handle h_to_module(THREAD, JNIHandles::resolve(to_module));
+  if (!java_lang_reflect_Module::is_instance(h_to_module())) {
+    return JVMTI_ERROR_INVALID_MODULE;
+  }
+  return JvmtiExport::add_module_reads(h_module, h_to_module, THREAD);
+} /* end AddModuleReads */
+
+
+// module - pre-checked for NULL
+// pkg_name - pre-checked for NULL
+// to_module - pre-checked for NULL
+jvmtiError
+JvmtiEnv::AddModuleExports(jobject module, const char* pkg_name, jobject to_module) {
+  JavaThread* THREAD = JavaThread::current();
+  Handle h_pkg = java_lang_String::create_from_str(pkg_name, THREAD);
+
+  // check module
+  Handle h_module(THREAD, JNIHandles::resolve(module));
+  if (!java_lang_reflect_Module::is_instance(h_module())) {
+    return JVMTI_ERROR_INVALID_MODULE;
+  }
+  // check to_module
+  Handle h_to_module(THREAD, JNIHandles::resolve(to_module));
+  if (!java_lang_reflect_Module::is_instance(h_to_module())) {
+    return JVMTI_ERROR_INVALID_MODULE;
+  }
+  return JvmtiExport::add_module_exports(h_module, h_pkg, h_to_module, THREAD);
+} /* end AddModuleExports */
+
+
+// module - pre-checked for NULL
+// pkg_name - pre-checked for NULL
+// to_module - pre-checked for NULL
+jvmtiError
+JvmtiEnv::AddModuleOpens(jobject module, const char* pkg_name, jobject to_module) {
+  JavaThread* THREAD = JavaThread::current();
+  Handle h_pkg = java_lang_String::create_from_str(pkg_name, THREAD);
+
+  // check module
+  Handle h_module(THREAD, JNIHandles::resolve(module));
+  if (!java_lang_reflect_Module::is_instance(h_module())) {
+    return JVMTI_ERROR_INVALID_MODULE;
+  }
+  // check to_module
+  Handle h_to_module(THREAD, JNIHandles::resolve(to_module));
+  if (!java_lang_reflect_Module::is_instance(h_to_module())) {
+    return JVMTI_ERROR_INVALID_MODULE;
+  }
+  return JvmtiExport::add_module_opens(h_module, h_pkg, h_to_module, THREAD);
+} /* end AddModuleOpens */
+
+
+// module - pre-checked for NULL
+// service - pre-checked for NULL
+jvmtiError
+JvmtiEnv::AddModuleUses(jobject module, jclass service) {
+  JavaThread* THREAD = JavaThread::current();
+
+  // check module
+  Handle h_module(THREAD, JNIHandles::resolve(module));
+  if (!java_lang_reflect_Module::is_instance(h_module())) {
+    return JVMTI_ERROR_INVALID_MODULE;
+  }
+  // check service
+  Handle h_service(THREAD, JNIHandles::resolve_external_guard(service));
+  if (!java_lang_Class::is_instance(h_service()) ||
+      java_lang_Class::is_primitive(h_service())) {
+    return JVMTI_ERROR_INVALID_CLASS;
+  }
+  return JvmtiExport::add_module_uses(h_module, h_service, THREAD);
+} /* end AddModuleUses */
+
+
+// module - pre-checked for NULL
+// service - pre-checked for NULL
+// impl_class - pre-checked for NULL
+jvmtiError
+JvmtiEnv::AddModuleProvides(jobject module, jclass service, jclass impl_class) {
+  JavaThread* THREAD = JavaThread::current();
+
+  // check module
+  Handle h_module(THREAD, JNIHandles::resolve(module));
+  if (!java_lang_reflect_Module::is_instance(h_module())) {
+    return JVMTI_ERROR_INVALID_MODULE;
+  }
+  // check service
+  Handle h_service(THREAD, JNIHandles::resolve_external_guard(service));
+  if (!java_lang_Class::is_instance(h_service()) ||
+      java_lang_Class::is_primitive(h_service())) {
+    return JVMTI_ERROR_INVALID_CLASS;
+  }
+  // check impl_class
+  Handle h_impl_class(THREAD, JNIHandles::resolve_external_guard(impl_class));
+  if (!java_lang_Class::is_instance(h_impl_class()) ||
+      java_lang_Class::is_primitive(h_impl_class())) {
+    return JVMTI_ERROR_INVALID_CLASS;
+  }
+  return JvmtiExport::add_module_provides(h_module, h_service, h_impl_class, THREAD);
+} /* end AddModuleProvides */
+
+
   //
   // Class functions
   //
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -434,6 +434,165 @@
   }
 }
 
+jvmtiError
+JvmtiExport::add_module_reads(Handle module, Handle to_module, TRAPS) {
+  if (!Universe::is_module_initialized()) {
+    return JVMTI_ERROR_NONE; // extra safety
+  }
+  assert(!module.is_null(), "module should always be set");
+  assert(!to_module.is_null(), "to_module should always be set");
+
+  // Invoke the addReads method
+  JavaValue result(T_VOID);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::module_Modules_klass(),
+                         vmSymbols::addReads_name(),
+                         vmSymbols::addReads_signature(),
+                         module,
+                         to_module,
+                         THREAD);
+
+  if (HAS_PENDING_EXCEPTION) {
+    LogTarget(Trace, jvmti) log;
+    LogStreamCHeap log_stream(log);
+    java_lang_Throwable::print(PENDING_EXCEPTION, &log_stream);
+    log_stream.cr();
+    CLEAR_PENDING_EXCEPTION;
+    return JVMTI_ERROR_INTERNAL;
+  }
+  return JVMTI_ERROR_NONE;
+}
+
+jvmtiError
+JvmtiExport::add_module_exports(Handle module, Handle pkg_name, Handle to_module, TRAPS) {
+  if (!Universe::is_module_initialized()) {
+    return JVMTI_ERROR_NONE; // extra safety
+  }
+  assert(!module.is_null(), "module should always be set");
+  assert(!to_module.is_null(), "to_module should always be set");
+  assert(!pkg_name.is_null(), "pkg_name should always be set");
+
+  // Invoke the addExports method
+  JavaValue result(T_VOID);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::module_Modules_klass(),
+                         vmSymbols::addExports_name(),
+                         vmSymbols::addExports_signature(),
+                         module,
+                         pkg_name,
+                         to_module,
+                         THREAD);
+
+  if (HAS_PENDING_EXCEPTION) {
+    Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
+    LogTarget(Trace, jvmti) log;
+    LogStreamCHeap log_stream(log);
+    java_lang_Throwable::print(PENDING_EXCEPTION, &log_stream);
+    log_stream.cr();
+    CLEAR_PENDING_EXCEPTION;
+    if (ex_name == vmSymbols::java_lang_IllegalArgumentException()) {
+      return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+    }
+    return JVMTI_ERROR_INTERNAL;
+  }
+  return JVMTI_ERROR_NONE;
+}
+
+jvmtiError
+JvmtiExport::add_module_opens(Handle module, Handle pkg_name, Handle to_module, TRAPS) {
+  if (!Universe::is_module_initialized()) {
+    return JVMTI_ERROR_NONE; // extra safety
+  }
+  assert(!module.is_null(), "module should always be set");
+  assert(!to_module.is_null(), "to_module should always be set");
+  assert(!pkg_name.is_null(), "pkg_name should always be set");
+
+  // Invoke the addOpens method
+  JavaValue result(T_VOID);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::module_Modules_klass(),
+                         vmSymbols::addOpens_name(),
+                         vmSymbols::addExports_signature(),
+                         module,
+                         pkg_name,
+                         to_module,
+                         THREAD);
+
+  if (HAS_PENDING_EXCEPTION) {
+    Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
+    LogTarget(Trace, jvmti) log;
+    LogStreamCHeap log_stream(log);
+    java_lang_Throwable::print(PENDING_EXCEPTION, &log_stream);
+    log_stream.cr();
+    CLEAR_PENDING_EXCEPTION;
+    if (ex_name == vmSymbols::java_lang_IllegalArgumentException()) {
+      return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+    }
+    return JVMTI_ERROR_INTERNAL;
+  }
+  return JVMTI_ERROR_NONE;
+}
+
+jvmtiError
+JvmtiExport::add_module_uses(Handle module, Handle service, TRAPS) {
+  if (!Universe::is_module_initialized()) {
+    return JVMTI_ERROR_NONE; // extra safety
+  }
+  assert(!module.is_null(), "module should always be set");
+  assert(!service.is_null(), "service should always be set");
+
+  // Invoke the addUses method
+  JavaValue result(T_VOID);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::module_Modules_klass(),
+                         vmSymbols::addUses_name(),
+                         vmSymbols::addUses_signature(),
+                         module,
+                         service,
+                         THREAD);
+
+  if (HAS_PENDING_EXCEPTION) {
+    LogTarget(Trace, jvmti) log;
+    LogStreamCHeap log_stream(log);
+    java_lang_Throwable::print(PENDING_EXCEPTION, &log_stream);
+    log_stream.cr();
+    CLEAR_PENDING_EXCEPTION;
+    return JVMTI_ERROR_INTERNAL;
+  }
+  return JVMTI_ERROR_NONE;
+}
+
+jvmtiError
+JvmtiExport::add_module_provides(Handle module, Handle service, Handle impl_class, TRAPS) {
+  if (!Universe::is_module_initialized()) {
+    return JVMTI_ERROR_NONE; // extra safety
+  }
+  assert(!module.is_null(), "module should always be set");
+  assert(!service.is_null(), "service should always be set");
+  assert(!impl_class.is_null(), "impl_class should always be set");
+
+  // Invoke the addProvides method
+  JavaValue result(T_VOID);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::module_Modules_klass(),
+                         vmSymbols::addProvides_name(),
+                         vmSymbols::addProvides_signature(),
+                         module,
+                         service,
+                         impl_class,
+                         THREAD);
+
+  if (HAS_PENDING_EXCEPTION) {
+    LogTarget(Trace, jvmti) log;
+    LogStreamCHeap log_stream(log);
+    java_lang_Throwable::print(PENDING_EXCEPTION, &log_stream);
+    log_stream.cr();
+    CLEAR_PENDING_EXCEPTION;
+    return JVMTI_ERROR_INTERNAL;
+  }
+  return JVMTI_ERROR_NONE;
+}
+
 void
 JvmtiExport::decode_version_values(jint version, int * major, int * minor,
                                    int * micro) {
--- a/hotspot/src/share/vm/prims/jvmtiExport.hpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp	Wed Jul 05 22:32:06 2017 +0200
@@ -218,6 +218,21 @@
   // Add read edges to the unnamed modules of the bootstrap and app class loaders
   static void add_default_read_edges(Handle h_module, TRAPS) NOT_JVMTI_RETURN;
 
+  // Add a read edge to the module
+  static jvmtiError add_module_reads(Handle module, Handle to_module, TRAPS);
+
+  // Updates a module to export a package
+  static jvmtiError add_module_exports(Handle module, Handle pkg_name, Handle to_module, TRAPS);
+
+  // Updates a module to open a package
+  static jvmtiError add_module_opens(Handle module, Handle pkg_name, Handle to_module, TRAPS);
+
+  // Add a used service to the module
+  static jvmtiError add_module_uses(Handle module, Handle service, TRAPS);
+
+  // Add a service provider to the module
+  static jvmtiError add_module_provides(Handle module, Handle service, Handle impl_class, TRAPS);
+
   // let JVMTI know that the JVM_OnLoad code is running
   static void enter_onload_phase() NOT_JVMTI_RETURN;
 
--- a/hotspot/src/share/vm/prims/whitebox.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/prims/whitebox.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -1415,14 +1415,6 @@
   Modules::add_reads_module(from_module, source_module, CHECK);
 WB_END
 
-WB_ENTRY(jboolean, WB_CanReadModule(JNIEnv* env, jobject o, jobject asking_module, jobject source_module))
-  return Modules::can_read_module(asking_module, source_module, THREAD);
-WB_END
-
-WB_ENTRY(jboolean, WB_IsExportedToModule(JNIEnv* env, jobject o, jobject from_module, jstring package, jobject to_module))
-  return Modules::is_exported_to_module(from_module, package, to_module, THREAD);
-WB_END
-
 WB_ENTRY(void, WB_AddModulePackage(JNIEnv* env, jobject o, jclass module, jstring package))
   Modules::add_module_package(module, package, CHECK);
 WB_END
@@ -1866,10 +1858,6 @@
                                                       (void*)&WB_AddModuleExports },
   {CC"AddReadsModule",     CC"(Ljava/lang/Object;Ljava/lang/Object;)V",
                                                       (void*)&WB_AddReadsModule },
-  {CC"CanReadModule",      CC"(Ljava/lang/Object;Ljava/lang/Object;)Z",
-                                                      (void*)&WB_CanReadModule },
-  {CC"IsExportedToModule", CC"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z",
-                                                      (void*)&WB_IsExportedToModule },
   {CC"AddModulePackage",   CC"(Ljava/lang/Object;Ljava/lang/String;)V",
                                                       (void*)&WB_AddModulePackage },
   {CC"GetModuleByPackageName", CC"(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;",
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -170,6 +170,8 @@
 #define ADDEXPORTS_LEN 10
 #define ADDREADS "addreads"
 #define ADDREADS_LEN 8
+#define ADDOPENS "addopens"
+#define ADDOPENS_LEN 8
 #define PATCH "patch"
 #define PATCH_LEN 5
 #define ADDMODS "addmods"
@@ -196,6 +198,7 @@
     const char* property_suffix = property + MODULE_PROPERTY_PREFIX_LEN;
     if (matches_property_suffix(property_suffix, ADDEXPORTS, ADDEXPORTS_LEN) ||
         matches_property_suffix(property_suffix, ADDREADS, ADDREADS_LEN) ||
+        matches_property_suffix(property_suffix, ADDOPENS, ADDOPENS_LEN) ||
         matches_property_suffix(property_suffix, PATCH, PATCH_LEN) ||
         matches_property_suffix(property_suffix, ADDMODS, ADDMODS_LEN) ||
         matches_property_suffix(property_suffix, LIMITMODS, LIMITMODS_LEN) ||
@@ -2555,6 +2558,7 @@
 
 unsigned int addreads_count = 0;
 unsigned int addexports_count = 0;
+unsigned int addopens_count = 0;
 unsigned int addmods_count = 0;
 unsigned int patch_mod_count = 0;
 
@@ -2809,6 +2813,10 @@
       if (!create_numbered_property("jdk.module.addexports", tail, addexports_count++)) {
         return JNI_ENOMEM;
       }
+    } else if (match_option(option, "--add-opens=", &tail)) {
+      if (!create_numbered_property("jdk.module.addopens", tail, addopens_count++)) {
+        return JNI_ENOMEM;
+      }
     } else if (match_option(option, "--add-modules=", &tail)) {
       if (!create_numbered_property("jdk.module.addmods", tail, addmods_count++)) {
         return JNI_ENOMEM;
--- a/hotspot/src/share/vm/runtime/javaCalls.cpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/runtime/javaCalls.cpp	Wed Jul 05 22:32:06 2017 +0200
@@ -285,6 +285,14 @@
 }
 
 
+void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, Handle arg3, TRAPS) {
+  JavaCallArguments args; // One oop argument
+  args.push_oop(arg1);
+  args.push_oop(arg2);
+  args.push_oop(arg3);
+  call_static(result, klass, name, signature, &args, CHECK);
+}
+
 // -------------------------------------------------
 // Implementation of JavaCalls (low level)
 
--- a/hotspot/src/share/vm/runtime/javaCalls.hpp	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/src/share/vm/runtime/javaCalls.hpp	Wed Jul 05 22:32:06 2017 +0200
@@ -210,6 +210,7 @@
   static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
   static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, TRAPS);
   static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, TRAPS);
+  static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, Handle arg3, TRAPS);
 
   // Low-level interface
   static void call(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS);
--- a/hotspot/test/TEST.ROOT	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/TEST.ROOT	Wed Jul 05 22:32:06 2017 +0200
@@ -47,8 +47,8 @@
     vm.gc.ConcMarkSweep \
     vm.debug
 
-# Tests using jtreg 4.2 b03 features
-requiredVersion=4.2 b03
+# Tests using jtreg 4.2 b04 features
+requiredVersion=4.2 b04
 
 # Path to libraries in the topmost test directory. This is needed so @library
 # does not need ../../ notation to reach them
--- a/hotspot/test/compiler/c2/Test7190310_unsafe.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/c2/Test7190310_unsafe.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,8 @@
  * @test
  * @bug 7190310
  * @summary Inlining WeakReference.get(), and hoisting $referent may lead to non-terminating loops
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
+ * @modules java.base/java.lang.ref:open
  *
  * @run main/othervm -Xbatch compiler.c2.Test7190310_unsafe
  */
--- a/hotspot/test/compiler/codegen/Test8011901.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/codegen/Test8011901.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8011901
  * @summary instruct xaddL_no_res shouldn't allow 64 bit constants.
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  *
  * @run main/othervm -XX:-BackgroundCompilation compiler.codegen.Test8011901
  */
--- a/hotspot/test/compiler/escapeAnalysis/TestUnsafePutAddressNullObjMustNotEscape.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/escapeAnalysis/TestUnsafePutAddressNullObjMustNotEscape.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8038048
  * @summary assert(null_obj->escape_state() == PointsToNode::NoEscape,etc)
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  *
  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DoEscapeAnalysis
  *      -XX:-TieredCompilation -Xbatch
--- a/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,8 @@
  * @bug 8130150 8131779 8139907
  * @summary Verify that the Montgomery multiply and square intrinsic works and correctly checks their arguments.
  * @requires vm.flavor == "server"
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.math:open
  * @library /test/lib
  *
  * @build sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/intrinsics/unsafe/AllocateUninitializedArray.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/intrinsics/unsafe/AllocateUninitializedArray.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8150465
  * @summary Unsafe methods to produce uninitialized arrays
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  *
  * @run main/othervm -ea -Diters=200   -Xint
  *      compiler.intrinsics.unsafe.AllocateUninitializedArray
--- a/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8136473
  * @summary Mismatched stores on same slice possible with Unsafe.Put*Unaligned methods
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  *
  * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation
  *      compiler.intrinsics.unsafe.TestUnsafeUnalignedMismatchedAccesses
--- a/hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6653795
  * @summary C2 intrinsic for Unsafe.getAddress performs pointer sign extension on 32-bit systems
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  *
  * @run main compiler.intrinsics.unsafe.UnsafeGetAddressTest
  */
--- a/hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8143930
  * @summary C1 LinearScan asserts when compiling two back-to-back CompareAndSwapLongs
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  *
  * @run testng/othervm -Diters=200000 -XX:TieredStopAtLevel=1
  *      compiler.intrinsics.unsafe.UnsafeTwoCASLong
--- a/hotspot/test/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,6 +30,7 @@
  *          java.compiler
  *          java.instrument
  *          java.management
+ *          jdk.attach
  *
  * @run main/othervm compiler.jsr292.RedefineMethodUsedByMultipleMethodHandles
  */
@@ -42,7 +43,6 @@
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import jdk.internal.org.objectweb.asm.Opcodes;
 
-import javax.tools.ToolProvider;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -132,7 +132,7 @@
         int p = vmName.indexOf('@');
         assert p != -1 : "VM name not in <pid>@<host> format: " + vmName;
         String pid = vmName.substring(0, p);
-        ClassLoader cl = ToolProvider.getSystemToolClassLoader();
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
         Class<?> c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl);
         Method attach = c.getDeclaredMethod("attach", String.class);
         Method loadAgent = c.getDeclaredMethod("loadAgent", String.class);
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,8 +27,8 @@
  * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
  * @library / /test/lib
  * @library ../common/patches
- * @modules java.base/jdk.internal.misc
- * @modules jdk.vm.ci/jdk.vm.ci.hotspot
+ * @modules java.base/jdk.internal.misc:+open
+ * @modules jdk.vm.ci/jdk.vm.ci.hotspot:+open
  *
  * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
  *        jdk.vm.ci/jdk.vm.ci.hotspot.PublicMetaspaceWrapperObject
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,10 +27,10 @@
  * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
  * @library / /test/lib
  * @library ../common/patches
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @modules java.base/jdk.internal.org.objectweb.asm
  *          java.base/jdk.internal.org.objectweb.asm.tree
- *          jdk.vm.ci/jdk.vm.ci.hotspot
+ * @modules         jdk.vm.ci/jdk.vm.ci.hotspot:+open
  *          jdk.vm.ci/jdk.vm.ci.code
  *          jdk.vm.ci/jdk.vm.ci.meta
  * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
--- a/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,8 +26,8 @@
  * @bug 8136421
  * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
  * @library /test/lib /
- * @modules java.base/jdk.internal.misc
- * @modules jdk.vm.ci/jdk.vm.ci.hotspot
+ * @modules java.base/jdk.internal.misc:open
+ * @modules jdk.vm.ci/jdk.vm.ci.hotspot:open
  *          jdk.vm.ci/jdk.vm.ci.runtime
  * @run main/othervm -XX:+UnlockExperimentalVMOptions
  *      -Dcompiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives.positive=true
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,9 +27,10 @@
  * @bug 8161068
  * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
  * @library /test/lib /compiler/jvmci/jdk.vm.ci.hotspot.test/src
+ * @modules java.base/java.lang.invoke:+open
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
- *          jdk.vm.ci/jdk.vm.ci.hotspot
+ * @modules         jdk.vm.ci/jdk.vm.ci.hotspot:+open
  * @run testng/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
  *      jdk.vm.ci.hotspot.test.MethodHandleAccessProviderTest
  */
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,6 +27,7 @@
  * @library ../../../../../
  * @modules jdk.vm.ci/jdk.vm.ci.meta
  *          jdk.vm.ci/jdk.vm.ci.runtime
+ *          jdk.attach
  *          java.base/jdk.internal.misc
  * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.RedefineClassTest
  */
@@ -37,7 +38,6 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import javax.tools.ToolProvider;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -137,7 +137,7 @@
         int p = vmName.indexOf('@');
         assumeTrue(p != -1);
         String pid = vmName.substring(0, p);
-        ClassLoader cl = ToolProvider.getSystemToolClassLoader();
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
         Class<?> c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl);
         Method attach = c.getDeclaredMethod("attach", String.class);
         Method loadAgent = c.getDeclaredMethod("loadAgent", String.class, String.class);
--- a/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8073480
  * @summary explicit range checks should be recognized by C2
  * @library /test/lib /
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
--- a/hotspot/test/compiler/runtime/Test8010927.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/runtime/Test8010927.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8010927
  * @summary Kitchensink crashed with SIGSEGV, Problematic frame: v ~StubRoutines::checkcast_arraycopy
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  *                                sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/compiler/unsafe/GetUnsafeObjectG1PreBarrier.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/GetUnsafeObjectG1PreBarrier.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8016474
  * @summary The bug only happens with C1 and G1 using a different ObjectAlignmentInBytes than KlassAlignmentInBytes (which is 8)
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:ObjectAlignmentInBytes=32
  *                   compiler.unsafe.GetUnsafeObjectG1PreBarrier
  */
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for boolean
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestBoolean
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestBoolean
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestBoolean
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for byte
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestByte
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestByte
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestByte
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for char
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestChar
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestChar
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestChar
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for double
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestDouble
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestDouble
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestDouble
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for float
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestFloat
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestFloat
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestFloat
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for int
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestInt
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestInt
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestInt
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for long
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestLong
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestLong
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestLong
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for Object
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestObject
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestObject
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestObject
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8143628
  * @summary Test unsafe access for short
  *
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  * @run testng/othervm -Diters=100   -Xint                   compiler.unsafe.JdkInternalMiscUnsafeAccessTestShort
  * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 compiler.unsafe.JdkInternalMiscUnsafeAccessTestShort
  * @run testng/othervm -Diters=20000 -XX:-TieredCompilation  compiler.unsafe.JdkInternalMiscUnsafeAccessTestShort
--- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeUnalignedAccess.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeUnalignedAccess.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8158260
  * @summary Test unaligned Unsafe accesses
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  *
  * @run main/othervm -Diters=20000 -XX:-UseOnStackReplacement -XX:-BackgroundCompilation
  *      compiler.unsafe.JdkInternalMiscUnsafeUnalignedAccess
--- a/hotspot/test/compiler/unsafe/TestUnsafeLoadControl.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/compiler/unsafe/TestUnsafeLoadControl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8077504
  * @summary Unsafe load can loose control dependency and cause crash
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:+open
  *
  * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement
  *                   compiler.unsafe.TestUnsafeLoadControl
--- a/hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,8 @@
  * @key gc
  * @requires vm.gc.G1
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  *          java.management
  */
 
--- a/hotspot/test/gc/g1/TestStringDeduplicationFullGC.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/g1/TestStringDeduplicationFullGC.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,8 @@
  * @key gc
  * @requires vm.gc.G1
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  *          java.management
  */
 
--- a/hotspot/test/gc/g1/TestStringDeduplicationInterned.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/g1/TestStringDeduplicationInterned.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,8 @@
  * @key gc
  * @requires vm.gc.G1
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  *          java.management
  */
 
--- a/hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,8 @@
  * @key gc
  * @requires vm.gc.G1
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  *          java.management
  */
 
--- a/hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,8 @@
  * @key gc
  * @requires vm.gc.G1
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  *          java.management
  */
 
--- a/hotspot/test/gc/g1/TestStringDeduplicationTableResize.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/g1/TestStringDeduplicationTableResize.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,8 @@
  * @key gc
  * @requires vm.gc.G1
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  *          java.management
  */
 
--- a/hotspot/test/gc/g1/TestStringDeduplicationTools.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/g1/TestStringDeduplicationTools.java	Wed Jul 05 22:32:06 2017 +0200
@@ -190,6 +190,7 @@
             "-Xmx" + Xmx + "m",
             "-XX:+UseG1GC",
             "-XX:+UnlockDiagnosticVMOptions",
+            "--add-opens=java.base/java.lang=ALL-UNNAMED",
             "-XX:+VerifyAfterGC" // Always verify after GC
         };
 
--- a/hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,8 @@
  * @key gc
  * @requires vm.gc.G1
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  *          java.management
  */
 
--- a/hotspot/test/gc/stress/gcbasher/TestGCBasher.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/gc/stress/gcbasher/TestGCBasher.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,7 +38,8 @@
         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
         Stream<Path> s = Files.walk(fs.getPath("/"));
         for (Path p : (Iterable<Path>)s::iterator) {
-            if (p.toString().endsWith(".class")) {
+            if (p.toString().endsWith(".class") &&
+                !p.getFileName().toString().equals("module-info.class")) {
                 byte[] data = Files.readAllBytes(p);
                 Decompiler d = new Decompiler(data);
                 ClassInfo ci = d.getClassInfo();
--- a/hotspot/test/runtime/LocalLong/LocalLongTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/LocalLong/LocalLongTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -39,6 +39,10 @@
     public static void main(String... args) throws Exception {
         if (Platform.is64bit()) {
             ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xint",
+                                                                      "--add-opens",
+                                                                      "java.base/java.lang=ALL-UNNAMED",
+                                                                      "--add-opens",
+                                                                      "java.base/java.lang.invoke=ALL-UNNAMED",
                                                                       "LocalLongHelper");
             OutputAnalyzer o = new OutputAnalyzer(pb.start());
             o.shouldHaveExitValue(0);
--- a/hotspot/test/runtime/Throwable/StackTraceLogging.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/Throwable/StackTraceLogging.java	Wed Jul 05 22:32:06 2017 +0200
@@ -52,6 +52,8 @@
     public static void main(String[] args) throws Exception {
         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:stacktrace=info",
                                                                   "-XX:MaxJavaStackTraceDepth=1024",
+                                                                  "--add-opens",
+                                                                  "java.base/java.lang=ALL-UNNAMED",
                                                                   "TestThrowable");
         analyzeOutputOn(pb);
     }
--- a/hotspot/test/runtime/Throwable/TestThrowable.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/Throwable/TestThrowable.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,8 @@
  * @test
  * @bug 8150778
  * @summary Test exception depths, and code to get stack traces
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  * @library /test/lib
  * @run main/othervm -XX:MaxJavaStackTraceDepth=1024 TestThrowable
  */
--- a/hotspot/test/runtime/Throwable/ThrowableIntrospectionSegfault.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/Throwable/ThrowableIntrospectionSegfault.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,8 @@
  * @test
  * @bug 8033735
  * @summary check backtrace field introspection
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  * @run main ThrowableIntrospectionSegfault
  */
 
--- a/hotspot/test/runtime/getSysPackage/GetSysPkgTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/getSysPackage/GetSysPkgTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -100,7 +100,7 @@
             ClassFileInstaller.writeClassToDisk("GetSysPkg_package/GetSysClass", klassbuf);
 
             ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xbootclasspath/a:bl_dir",
-                "--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED", "-cp", "." + File.pathSeparator +
+                "--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED", "-cp", "." + File.pathSeparator +
                 System.getProperty("test.classes"), "GetSysPkgTest", "do_tests");
             OutputAnalyzer output = new OutputAnalyzer(pb.start());
             output.shouldHaveExitValue(0);
--- a/hotspot/test/runtime/modules/AccessCheck/CheckRead.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/CheckRead.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,7 +69,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m3")
                         .exports("p1")
@@ -80,9 +80,9 @@
         // Packages:          p2
         // Packages exported: p2 is exported to m1
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m1")
+                        .exports("p2", Set.of("m1"))
                         .build();
 
         // Define module:     m3
@@ -90,10 +90,10 @@
         // Packages:          p3
         // Packages exported: none
         ModuleDescriptor descriptor_m3 =
-                new ModuleDescriptor.Builder("m3")
+                ModuleDescriptor.module("m3")
                         .requires("java.base")
                         .requires("m2")
-                        .conceals("p3")
+                        .contains("p3")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/DiffCL_CheckRead.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_CheckRead.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,7 +69,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m3")
                         .exports("p1")
@@ -80,9 +80,9 @@
         // Packages:          p2
         // Packages exported: p2 is exported to m1
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m1")
+                        .exports("p2", Set.of("m1"))
                         .build();
 
         // Define module:     m3
@@ -90,10 +90,10 @@
         // Packages:          p3
         // Packages exported: none
         ModuleDescriptor descriptor_m3 =
-                new ModuleDescriptor.Builder("m3")
+                ModuleDescriptor.module("m3")
                         .requires("java.base")
                         .requires("m2")
-                        .conceals("p3")
+                        .contains("p3")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualOther.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualOther.java	Wed Jul 05 22:32:06 2017 +0200
@@ -70,7 +70,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .requires("m3")
@@ -82,9 +82,9 @@
         // Packages:          p2
         // Packages exported: p2 is exported to m3
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m3")
+                        .exports("p2", Set.of("m3"))
                         .build();
 
         // Define module:     m3
@@ -92,10 +92,10 @@
         // Packages:          p3
         // Packages exported: none
         ModuleDescriptor descriptor_m3 =
-                new ModuleDescriptor.Builder("m3")
+                ModuleDescriptor.module("m3")
                         .requires("java.base")
                         .requires("m2")
-                        .conceals("p3")
+                        .contains("p3")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualToM1.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualToM1.java	Wed Jul 05 22:32:06 2017 +0200
@@ -68,7 +68,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported to unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .exports("p1")
@@ -79,9 +79,9 @@
         // Packages:          p2
         // Packages exported: package p2 is exported to m1
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m1")
+                        .exports("p2", Set.of("m1"))
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpUnqual.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpUnqual.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,7 +69,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .exports("p1")
@@ -80,7 +80,7 @@
         // Packages:          p2
         // Packages exported: package p2 is exported to m1
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
                         .exports("p2")
                         .build();
--- a/hotspot/test/runtime/modules/AccessCheck/DiffCL_PkgNotExp.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_PkgNotExp.java	Wed Jul 05 22:32:06 2017 +0200
@@ -68,7 +68,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .exports("p1")
@@ -79,9 +79,9 @@
         // Packages:          p2
         // Packages exported: none
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .conceals("p2")
+                        .contains("p2")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/DiffCL_Umod.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_Umod.java	Wed Jul 05 22:32:06 2017 +0200
@@ -80,7 +80,7 @@
      // Packages:          p1
      // Packages exported: p1 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p1")
                      .build();
@@ -129,7 +129,7 @@
      // Packages:          p1
      // Packages exported: p1 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p1")
                      .build();
@@ -178,7 +178,7 @@
      // Packages:          p1
      // Packages exported: p1 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p1")
                      .build();
--- a/hotspot/test/runtime/modules/AccessCheck/DiffCL_UmodUpkg.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_UmodUpkg.java	Wed Jul 05 22:32:06 2017 +0200
@@ -75,7 +75,7 @@
      // Packages:          p3
      // Packages exported: p3 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p3")
                      .build();
@@ -124,7 +124,7 @@
      // Packages:          p3
      // Packages exported: p3 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p3")
                      .build();
--- a/hotspot/test/runtime/modules/AccessCheck/ExpQualOther.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/ExpQualOther.java	Wed Jul 05 22:32:06 2017 +0200
@@ -70,7 +70,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .requires("m3")
@@ -82,9 +82,9 @@
         // Packages:          p2
         // Packages exported: p2 is exported to m3
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m3")
+                        .exports("p2", Set.of("m3"))
                         .build();
 
         // Define module:     m3
@@ -92,10 +92,10 @@
         // Packages:          p3
         // Packages exported: none
         ModuleDescriptor descriptor_m3 =
-                new ModuleDescriptor.Builder("m3")
+                ModuleDescriptor.module("m3")
                         .requires("java.base")
                         .requires("m2")
-                        .conceals("p3")
+                        .contains("p3")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/ExpQualToM1.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/ExpQualToM1.java	Wed Jul 05 22:32:06 2017 +0200
@@ -58,7 +58,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .exports("p1")
@@ -69,9 +69,9 @@
         // Packages:          p2
         // Packages exported: p2 is exported qualifiedly to m1
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m1")
+                        .exports("p2", Set.of("m1"))
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/ExpUnqual.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/ExpUnqual.java	Wed Jul 05 22:32:06 2017 +0200
@@ -58,7 +58,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .exports("p1")
@@ -69,7 +69,7 @@
         // Packages:          p2
         // Packages exported: p2 is exported unqualifiedly
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
                         .exports("p2")
                         .build();
--- a/hotspot/test/runtime/modules/AccessCheck/ExportAllUnnamed.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/ExportAllUnnamed.java	Wed Jul 05 22:32:06 2017 +0200
@@ -71,7 +71,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -81,9 +81,9 @@
         // Packages:          p2
         // Packages exported: p2 is exported unqualifiedly
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m1")
+                        .exports("p2", Set.of("m1"))
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/PkgNotExp.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/PkgNotExp.java	Wed Jul 05 22:32:06 2017 +0200
@@ -68,7 +68,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .exports("p1")
@@ -79,9 +79,9 @@
         // Packages:          p2
         // Packages exported: none
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .conceals("p2")
+                        .contains("p2")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/Umod.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/Umod.java	Wed Jul 05 22:32:06 2017 +0200
@@ -80,7 +80,7 @@
      // Packages:          p1
      // Packages exported: p1 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p1")
                      .build();
@@ -126,7 +126,7 @@
      // Packages:          p1
      // Packages exported: p1 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p1")
                      .build();
@@ -172,7 +172,7 @@
      // Packages:          p1
      // Packages exported: p1 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p1")
                      .build();
--- a/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpQualOther.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpQualOther.java	Wed Jul 05 22:32:06 2017 +0200
@@ -70,7 +70,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -80,9 +80,9 @@
         // Packages:          p2
         // Packages exported: none
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m1")
+                        .exports("p2", Set.of("m1"))
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpUnqual.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpUnqual.java	Wed Jul 05 22:32:06 2017 +0200
@@ -70,7 +70,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -80,7 +80,7 @@
         // Packages:          p2
         // Packages exported: none
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
                         .exports("p2")
                         .build();
--- a/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_PkgNotExp.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_PkgNotExp.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,7 +69,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -79,9 +79,9 @@
         // Packages:          p2
         // Packages exported: none
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .conceals("p2")
+                        .contains("p2")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/UmodUPkg.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/UmodUPkg.java	Wed Jul 05 22:32:06 2017 +0200
@@ -75,7 +75,7 @@
      // Packages:          p3
      // Packages exported: p3 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p3")
                      .build();
@@ -121,7 +121,7 @@
      // Packages:          p3
      // Packages exported: p3 is exported unqualifiedly
      ModuleDescriptor descriptor_m1 =
-             new ModuleDescriptor.Builder("m1")
+             ModuleDescriptor.module("m1")
                      .requires("java.base")
                      .exports("p3")
                      .build();
--- a/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_ExpQualOther.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_ExpQualOther.java	Wed Jul 05 22:32:06 2017 +0200
@@ -70,7 +70,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -80,9 +80,9 @@
         // Packages:          p6
         // Packages exported: p6 exported to m1
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p6", "m1")
+                        .exports("p6", Set.of("m1"))
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_NotExp.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_NotExp.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,7 +69,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -79,9 +79,9 @@
         // Packages:          p6
         // Packages exported: none
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .conceals("p6")
+                        .contains("p6")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_ExpQualOther.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_ExpQualOther.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,7 +69,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .requires("m3")
@@ -80,9 +80,9 @@
         // Packages:          p6
         // Packages exported: p6 is exported to m3
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p6", "m3")
+                        .exports("p6", Set.of("m3"))
                         .build();
 
         // Define module:     m3
@@ -90,7 +90,7 @@
         // Packages:          p3
         // Packages exported: none
         ModuleDescriptor descriptor_m3 =
-                new ModuleDescriptor.Builder("m3")
+                ModuleDescriptor.module("m3")
                         .requires("java.base")
                         .build();
 
--- a/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_NotExp.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_NotExp.java	Wed Jul 05 22:32:06 2017 +0200
@@ -67,7 +67,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -77,9 +77,9 @@
         // Packages:          p6
         // Packages exported: none
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .conceals("p6")
+                        .contains("p6")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/AccessCheck/Umod_ExpQualOther.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/Umod_ExpQualOther.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,7 +69,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .requires("m3")
@@ -80,9 +80,9 @@
         // Packages:          p2
         // Packages exported: p2 is exported to m3
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m3")
+                        .exports("p2", Set.of("m3"))
                         .build();
 
         // Define module:     m3
@@ -90,7 +90,7 @@
         // Packages:          p3
         // Packages exported: none
         ModuleDescriptor descriptor_m3 =
-                new ModuleDescriptor.Builder("m3")
+                ModuleDescriptor.module("m3")
                         .requires("java.base")
                         .build();
 
--- a/hotspot/test/runtime/modules/AccessCheck/Umod_ExpUnqual.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/Umod_ExpUnqual.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,7 +69,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -79,7 +79,7 @@
         // Packages:          p2
         // Packages exported: p2 is exported unqualifiedly
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
                         .exports("p2")
                         .build();
--- a/hotspot/test/runtime/modules/AccessCheck/Umod_PkgNotExp.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/AccessCheck/Umod_PkgNotExp.java	Wed Jul 05 22:32:06 2017 +0200
@@ -67,7 +67,7 @@
         // Packages:          none
         // Packages exported: none
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .build();
@@ -77,9 +77,9 @@
         // Packages:          p2
         // Packages exported: none
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .conceals("p2")
+                        .contains("p2")
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/IgnoreModulePropertiesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/IgnoreModulePropertiesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -72,6 +72,6 @@
         testOption("--add-reads", "xyzz=yyzd", "jdk.module.addreads.0", "WARNING: Unknown module: xyzz");
         testOption("--add-exports", "java.base/xyzz=yyzd", "jdk.module.addexports.0",
                    "WARNING: package xyzz not in java.base");
-        testOption("--patch-module", "=d", "jdk.module.patch.0", "IllegalArgumentException");
+        testOption("--patch-module", "=d", "jdk.module.patch.0", "Missing module name");
     }
 }
--- a/hotspot/test/runtime/modules/JVMAddModulePackage.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/JVMAddModulePackage.java	Wed Jul 05 22:32:06 2017 +0200
@@ -33,6 +33,7 @@
  */
 
 import static jdk.test.lib.Asserts.*;
+import java.sql.Time;
 
 public class JVMAddModulePackage {
 
@@ -123,6 +124,29 @@
             // Expected
         }
 
+        // Add package named "java" to an module defined to a class loader other than the boot or platform loader.
+        try {
+            // module1 is defined to a MyClassLoader class loader.
+            ModuleHelper.AddModulePackage(module1, "java/foo");
+            throw new RuntimeException("Failed to get the expected IAE");
+        } catch(IllegalArgumentException e) {
+            if (!e.getMessage().contains("prohibited package name")) {
+              throw new RuntimeException("Failed to get expected IAE message for prohibited package name: " + e.getMessage());
+            }
+        }
+
+        // Package "javabar" should be ok
+        ModuleHelper.AddModulePackage(module1, "javabar");
+
+        // Package named "java" defined to the boot class loader, should be ok
+        Object module_javabase = module1.getClass().getModule();
+        ModuleHelper.AddModulePackage(module_javabase, "java/foo");
+
+        // Package named "java" defined to the platform class loader, should be ok
+        // The module java.sql is defined to the platform class loader.
+        java.sql.Time jst = new java.sql.Time(45000); // milliseconds
+        Object module_javasql = jst.getClass().getModule();
+        ModuleHelper.AddModulePackage(module_javasql, "java/foo");
     }
 
     static class MyClassLoader extends ClassLoader { }
--- a/hotspot/test/runtime/modules/JVMCanReadModule.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * 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
- * @modules java.base/jdk.internal.misc
- * @library /test/lib ..
- * @build sun.hotspot.WhiteBox
- * @compile/module=java.base java/lang/reflect/ModuleHelper.java
- * @run main ClassFileInstaller sun.hotspot.WhiteBox
- *                              sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMCanReadModule
- */
-
-import static jdk.test.lib.Asserts.*;
-
-public class JVMCanReadModule {
-
-    public static void main(String args[]) throws Throwable {
-        MyClassLoader asking_cl = new MyClassLoader();
-        MyClassLoader target_cl = new MyClassLoader();
-        Object asking_module, target_module;
-        boolean result;
-
-        asking_module = ModuleHelper.ModuleObject("asking_module", asking_cl, new String[] { "mypackage" });
-        assertNotNull(asking_module, "Module should not be null");
-        ModuleHelper.DefineModule(asking_module, "9.0", "asking_module/here", new String[] { "mypackage" });
-        target_module = ModuleHelper.ModuleObject("target_module", target_cl, new String[] { "yourpackage" });
-        assertNotNull(target_module, "Module should not be null");
-        ModuleHelper.DefineModule(target_module, "9.0", "target_module/here", new String[] { "yourpackage" });
-
-        // Set up relationship
-        ModuleHelper.AddReadsModule(asking_module, target_module);
-
-        // Null asking_module argument, expect an NPE
-        try {
-            result = ModuleHelper.CanReadModule(null, target_module);
-            throw new RuntimeException("Failed to get the expected NPE");
-        } catch(NullPointerException e) {
-            // Expected
-        }
-
-        // Bad asking_module argument, expect an IAE
-        try {
-            result = ModuleHelper.CanReadModule(asking_cl, target_module);
-            throw new RuntimeException("Failed to get the expected IAE");
-        } catch(IllegalArgumentException e) {
-            // Expected
-        }
-
-        // Bad target_module argument, expect an IAE
-        try {
-            result = ModuleHelper.CanReadModule(asking_module, asking_cl);
-            throw new RuntimeException("Failed to get the expected IAE");
-        } catch(IllegalArgumentException e) {
-            // Expected
-        }
-
-        // Verify strict modules can not read the unnamed module
-        result = ModuleHelper.CanReadModule(target_module, null);
-        assertFalse(result, "target_module can not read unnamed module");
-
-        // Verify asking_module can read itself
-        result = ModuleHelper.CanReadModule(asking_module, asking_module);
-        assertTrue(result, "asking_module can read itself");
-
-        // Verify asking_module can read target_module
-        result = ModuleHelper.CanReadModule(asking_module, target_module);
-        assertTrue(result, "asking_module can read target_module");
-
-        // Verify target_module cannot read asking_module
-        result = ModuleHelper.CanReadModule(target_module, asking_module);
-        assertTrue(!result, "target_module cannot read asking_module");
-    }
-
-    static class MyClassLoader extends ClassLoader { }
-}
--- a/hotspot/test/runtime/modules/JVMDefineModule.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/JVMDefineModule.java	Wed Jul 05 22:32:06 2017 +0200
@@ -33,6 +33,7 @@
  */
 
 import static jdk.test.lib.Asserts.*;
+import java.sql.Time;
 
 public class JVMDefineModule {
 
@@ -238,6 +239,39 @@
             }
         }
 
+        // Package named "java" defined to a class loader other than the boot or platform class loader, expect an IAE
+        m = ModuleHelper.ModuleObject("modulejavapkg1", cl, new String[] { "java/foo" });
+        try {
+            // module m is defined to an instance of MyClassLoader class loader
+            ModuleHelper.DefineModule(m, "9.0", "modulejavapkg1", new String[] { "java/foo" });
+            throw new RuntimeException("Failed to get expected IAE for package java/foo");
+        } catch(IllegalArgumentException e) {
+            if (!e.getMessage().contains("prohibited package name")) {
+              throw new RuntimeException("Failed to get expected IAE message for prohibited package name: " + e.getMessage());
+            }
+        }
+
+        // Package named "javabar" defined to a class loader other than the boot or platform class loader, should be ok
+        m = ModuleHelper.ModuleObject("modulejavapkg2", cl, new String[] { "javabar" });
+        assertNotNull(m, "Module should not be null");
+        ModuleHelper.DefineModule(m, "9.0", "modulejavapkg2", new String[] { "javabar" });
+
+        // Package named "java" defined to the boot class loader, should be ok
+        //   m's type is a java.lang.Object, module is java.base
+        //   java.base module is defined to the boot loader
+        ClassLoader boot_loader = m.getClass().getClassLoader();
+        m = ModuleHelper.ModuleObject("modulejavapkg3", boot_loader, new String[] { "java/foo" });
+        assertNotNull(m, "Module should not be null");
+        ModuleHelper.DefineModule(m, "9.0", "modulejavapkg3", new String[] { "java/foo" });
+
+        // Package named "java" defined to the platform class loader, should be ok
+        //   java.sql module defined to the platform class loader.
+        java.sql.Time jst = new java.sql.Time(45 * 1000);
+        ClassLoader platform_loader = jst.getClass().getClassLoader();
+        m = ModuleHelper.ModuleObject("modulejavapkg4", platform_loader, new String[] { "java/foo" });
+        assertNotNull(m, "Module should not be null");
+        ModuleHelper.DefineModule(m, "9.0", "modulejavapkg4", new String[] { "java/foo" });
+
         // module version that is null, should be okay
         m = ModuleHelper.ModuleObject("module8", cl, new String[] { "a_package_8" });
         assertNotNull(m, "Module should not be null");
--- a/hotspot/test/runtime/modules/JVMIsExportedToModule.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * 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
- * @modules java.base/jdk.internal.misc
- * @library /test/lib ..
- * @build sun.hotspot.WhiteBox
- * @compile/module=java.base java/lang/reflect/ModuleHelper.java
- * @run main ClassFileInstaller sun.hotspot.WhiteBox
- *                              sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMIsExportedToModule
- */
-
-import static jdk.test.lib.Asserts.*;
-
-public class JVMIsExportedToModule {
-
-    public static void main(String args[]) throws Throwable {
-        MyClassLoader from_cl = new MyClassLoader();
-        MyClassLoader to_cl = new MyClassLoader();
-        Object from_module, to_module;
-        boolean result;
-
-        from_module = ModuleHelper.ModuleObject("from_module", from_cl, new String[] { "mypackage", "this/package" });
-        assertNotNull(from_module, "Module from_module should not be null");
-        ModuleHelper.DefineModule(from_module, "9.0", "from_module/here", new String[] { "mypackage", "this/package" });
-        to_module = ModuleHelper.ModuleObject("to_module", to_cl, new String[] { "yourpackage", "that/package" });
-        assertNotNull(to_module, "Module to_module should not be null");
-        ModuleHelper.DefineModule(to_module, "9.0", "to_module/here", new String[] { "yourpackage", "that/package" });
-
-        Object unnamed_module = JVMIsExportedToModule.class.getModule();
-        assertNotNull(unnamed_module, "Module unnamed_module should not be null");
-
-        // Null from_module argument, expect an NPE
-        try {
-            result = ModuleHelper.IsExportedToModule(null, "mypackage", to_module);
-            throw new RuntimeException("Failed to get the expected NPE for null from_module");
-        } catch(NullPointerException e) {
-            // Expected
-        }
-
-        // Null to_module argument, expect an NPE
-        try {
-          result = ModuleHelper.IsExportedToModule(from_module, "mypackage", null);
-          throw new RuntimeException("Failed to get expected NPE for null to_module");
-        } catch(NullPointerException e) {
-            // Expected
-        }
-
-        // Null package argument, expect an NPE
-        try {
-            result = ModuleHelper.IsExportedToModule(from_module, null, to_module);
-            throw new RuntimeException("Failed to get the expected NPE for null package");
-        } catch(NullPointerException e) {
-            // Expected
-        }
-
-        // Bad from_module argument, expect an IAE
-        try {
-            result = ModuleHelper.IsExportedToModule(to_cl, "mypackage", to_module);
-            throw new RuntimeException("Failed to get the expected IAE for bad from_module");
-        } catch(IllegalArgumentException e) {
-            // Expected
-        }
-
-        // Bad to_module argument, expect an IAE
-        try {
-            result = ModuleHelper.IsExportedToModule(from_module, "mypackage", from_cl);
-            throw new RuntimeException("Failed to get the expected IAE");
-        } catch(IllegalArgumentException e) {
-            // Expected
-        }
-
-        // Check that package is exported to its own module
-        result = ModuleHelper.IsExportedToModule(from_module, "mypackage", from_module);
-        assertTrue(result, "Package is always exported to itself");
-
-        // Package is not in to_module, expect an IAE
-        try {
-            result = ModuleHelper.IsExportedToModule(from_module, "yourpackage", from_cl);
-            throw new RuntimeException("Failed to get the expected IAE for package not in to_module");
-        } catch(IllegalArgumentException e) {
-            // Expected
-        }
-
-        // Package is accessible when exported to unnamed module
-        ModuleHelper.AddModuleExportsToAll(from_module, "mypackage");
-        result = ModuleHelper.IsExportedToModule(from_module, "mypackage", to_module);
-        assertTrue(result, "Package exported to unnamed module is visible to named module");
-
-        result = ModuleHelper.IsExportedToModule(from_module, "mypackage", unnamed_module);
-        assertTrue(result, "Package exported to unnamed module is visible to unnamed module");
-
-        // Package is accessible only to named module when exported to named module
-        ModuleHelper.AddModuleExports(from_module, "this/package", to_module);
-        result = ModuleHelper.IsExportedToModule(from_module, "this/package", to_module);
-        assertTrue(result, "Package exported to named module is visible to named module");
-        result = ModuleHelper.IsExportedToModule(from_module, "this/package", unnamed_module);
-        assertTrue(!result, "Package exported to named module is not visible to unnamed module");
-    }
-
-    static class MyClassLoader extends ClassLoader { }
-}
--- a/hotspot/test/runtime/modules/ModuleHelper.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/ModuleHelper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -73,17 +73,6 @@
         java.lang.reflect.ModuleHelper.addExportsNoSync((Module)m, pkg, (Module)null);
     }
 
-    public static boolean CanReadModule(Object from, Object to) throws Throwable {
-        WhiteBox wb = WhiteBox.getWhiteBox();
-        return wb.CanReadModule(from, to);
-    }
-
-    public static boolean IsExportedToModule(Object from, String pkg,
-                                             Object to) throws Throwable {
-        WhiteBox wb = WhiteBox.getWhiteBox();
-        return wb.IsExportedToModule(from, pkg, to);
-    }
-
     public static Module ModuleObject(String name, ClassLoader loader, String[] pkgs) throws Throwable {
         Set<String> pkg_set = new HashSet<>();
         if (pkgs != null) {
@@ -95,7 +84,7 @@
         }
 
         ModuleDescriptor descriptor =
-            new ModuleDescriptor.Builder(name).conceals(pkg_set).build();
+            ModuleDescriptor.module(name).contains(pkg_set).build();
         URI uri = URI.create("module:/" + name);
 
         return java.lang.reflect.ModuleHelper.newModule(loader, descriptor);
--- a/hotspot/test/runtime/modules/ModuleStress/ModuleNonBuiltinCLMain.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/ModuleStress/ModuleNonBuiltinCLMain.java	Wed Jul 05 22:32:06 2017 +0200
@@ -57,7 +57,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported to unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .exports("p1")
@@ -71,7 +71,7 @@
         targets.add("m1");
         targets.add("m3");
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
                         .requires("m3")
                         .exports("p2", targets)
@@ -82,7 +82,7 @@
         // Packages:          p3
         // Packages exported: none
         ModuleDescriptor descriptor_m3 =
-                new ModuleDescriptor.Builder("m3")
+                ModuleDescriptor.module("m3")
                         .requires("java.base")
                         .build();
 
--- a/hotspot/test/runtime/modules/ModuleStress/ModuleSameCLMain.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/ModuleStress/ModuleSameCLMain.java	Wed Jul 05 22:32:06 2017 +0200
@@ -55,7 +55,7 @@
         // Packages:          p1
         // Packages exported: p1 is exported to unqualifiedly
         ModuleDescriptor descriptor_m1 =
-                new ModuleDescriptor.Builder("m1")
+                ModuleDescriptor.module("m1")
                         .requires("java.base")
                         .requires("m2")
                         .exports("p1")
@@ -66,9 +66,9 @@
         // Packages:          p2
         // Packages exported: package p2 is exported to m1
         ModuleDescriptor descriptor_m2 =
-                new ModuleDescriptor.Builder("m2")
+                ModuleDescriptor.module("m2")
                         .requires("java.base")
-                        .exports("p2", "m1")
+                        .exports("p2", Set.of("m1"))
                         .build();
 
         // Set up a ModuleFinder containing all modules for this layer.
--- a/hotspot/test/runtime/modules/getModuleJNI/GetModule.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/getModuleJNI/GetModule.java	Wed Jul 05 22:32:06 2017 +0200
@@ -35,10 +35,6 @@
     }
 
     static native Object callGetModule(java.lang.Class clazz);
-    static native void callAddModuleReads(java.lang.reflect.Module from_module,
-                                          java.lang.reflect.Module source_module);
-    static native boolean callCanReadModule(java.lang.reflect.Module asking_module,
-                                            java.lang.reflect.Module source_module);
 
     public static void main(String[] args) {
         Module module;
@@ -144,71 +140,6 @@
         } catch(NullPointerException e) {
             // Expected
         }
-
-
-        // Tests for JNI_AddModuleReads() //
-
-        Module javaScriptingModule = javax.script.Bindings.class.getModule();
-        if (javaScriptingModule == null) {
-            throw new RuntimeException("Failed to get java.scripting module");
-        }
-        Module javaLoggingModule = java.util.logging.Level.class.getModule();
-        if (javaLoggingModule == null) {
-            throw new RuntimeException("Failed to get java.logging module");
-        }
-
-        if (callCanReadModule(javaLoggingModule, javaScriptingModule)) {
-            throw new RuntimeException(
-                "Expected FALSE because javaLoggingModule cannot read javaScriptingModule");
-        }
-
-        callAddModuleReads(javaLoggingModule, javaScriptingModule);
-        callAddModuleReads(javaScriptingModule, GetModule.class.getModule()); // unnamed module
-
-        try {
-            callAddModuleReads(null, javaLoggingModule);
-            throw new RuntimeException(
-                "Expected NullPointerException for bad from_module not thrown");
-        } catch(NullPointerException e) {
-            // expected
-        }
-
-        try {
-          callAddModuleReads(javaLoggingModule, null);
-          throw new RuntimeException(
-                "Expected NullPointerException for bad source_module not thrown");
-        } catch(NullPointerException e) {
-            // expected
-        }
-
-
-        // Tests for JNI_CanReadModule() //
-
-        if (!callCanReadModule(javaLoggingModule, javaScriptingModule)) {
-            throw new RuntimeException(
-                "Expected TRUE because javaLoggingModule can read javaScriptingModule");
-        }
-
-        if (callCanReadModule(javaBaseModule, javaScriptingModule)) {
-            throw new RuntimeException(
-                "Expected FALSE because javaBaseModule cannnot read javaScriptingModule");
-        }
-
-        try {
-            callCanReadModule(javaLoggingModule, null);
-            throw new RuntimeException(
-                "Expected NullPointerException for bad sourceModule not thrown");
-        } catch(NullPointerException e) {
-            // expected
-        }
-
-        try {
-            callCanReadModule(null, javaScriptingModule);
-            throw new RuntimeException(
-                "Expected NullPointerException for bad asking_module not thrown");
-        } catch(NullPointerException e) {
-            // expected
-        }
     }
 
     static class MyClassLoader extends ClassLoader { }
--- a/hotspot/test/runtime/modules/getModuleJNI/libGetModule.c	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/runtime/modules/getModuleJNI/libGetModule.c	Wed Jul 05 22:32:06 2017 +0200
@@ -28,15 +28,3 @@
     jobject res = (jobject)((*env)->GetModule(env, clazz));
     return res;
 }
-
-JNIEXPORT void JNICALL
-Java_GetModule_callAddModuleReads(JNIEnv *env, jclass unused, jobject from_module, jobject source_module) {
-    (*env)->AddModuleReads(env, from_module, source_module);
-}
-
-JNIEXPORT jboolean JNICALL
-Java_GetModule_callCanReadModule(JNIEnv *env, jclass unused, jobject asking_module, jobject source_module) {
-   jboolean res = (*env)->CanReadModule(env, asking_module, source_module);
-   return res;
-}
-
--- a/hotspot/test/serviceability/attach/AttachWithStalePidFile.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/serviceability/attach/AttachWithStalePidFile.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,8 @@
  * @bug 7162400
  * @key regression
  * @summary Regression test for attach issue where stale pid files in /tmp lead to connection issues
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.misc:open
+ * @modules java.base/java.lang:open
  * @modules jdk.attach/sun.tools.attach
  * @library /test/lib
  * @run main AttachWithStalePidFile
--- a/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,7 +32,7 @@
  * @test
  * @summary Tests the modules-related JDWP commands
  * @library /test/lib
- * @ignore 8168478
+ * @ignore 8170541
  * @modules jdk.jdwp.agent
  * @modules java.base/jdk.internal.misc
  * @compile AllModulesCommandTestDebuggee.java
@@ -96,8 +96,7 @@
                 if (modName != null) { // JDWP reports unnamed modules, ignore them
                     jdwpModuleNames.add(modName);
                 }
-                // Assert the JDWP CANREAD and CLASSLOADER commands
-                assertCanRead(modId, modName);
+                // Assert the CLASSLOADER commands
                 assertClassLoader(modId, modName);
             }
 
@@ -134,13 +133,6 @@
         }
     }
 
-    private void assertCanRead(long modId, String modName) throws IOException {
-        // Simple assert for the CANREAD command
-        JdwpCanReadReply reply = new JdwpCanReadCmd(modId, modId).send(channel);
-        assertReply(reply);
-        assertTrue(reply.canRead(), "canRead() reports false for reading from the same module '" + modName + "', moduleId=" + modId);
-    }
-
     private void assertClassLoader(long modId, String modName) throws IOException {
         // Verify that the module classloader id is valid
         JdwpClassLoaderReply reply = new JdwpClassLoaderCmd(modId).send(channel);
--- a/hotspot/test/serviceability/jdwp/JdwpCanReadCmd.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * The JDWP CANREAD command
- */
-public class JdwpCanReadCmd extends JdwpCmd<JdwpCanReadReply> {
-
-    public JdwpCanReadCmd(long modId, long srcModId) {
-        super(3, 18, JdwpCanReadReply.class, 2 * refLen());
-        putRefId(modId);
-        putRefId(srcModId);
-    }
-
-}
--- a/hotspot/test/serviceability/jdwp/JdwpCanReadReply.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * 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.DataInputStream;
-import java.io.IOException;
-
-/**
- * The reply to the JDWP CANREAD command
- */
-public class JdwpCanReadReply extends JdwpReply {
-
-    private boolean canRead;
-
-    protected void parseData(DataInputStream ds) throws IOException {
-        canRead = (ds.read() != 0);
-    }
-
-    public boolean canRead() {
-        return canRead;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/AddModuleExportsAndOpens/MyPackage/AddModuleExportsAndOpensTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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 MyPackage;
+
+/**
+ * @test
+ * @summary Verifies the JVMTI AddModuleExports and AddModuleOpens API
+ * @compile AddModuleExportsAndOpensTest.java
+ * @run main/othervm/native -agentlib:AddModuleExportsAndOpensTest MyPackage.AddModuleExportsAndOpensTest
+ */
+
+import java.io.PrintStream;
+import java.lang.reflect.Module;
+
+public class AddModuleExportsAndOpensTest {
+
+    static {
+        try {
+            System.loadLibrary("AddModuleExportsAndOpensTest");
+        } catch (UnsatisfiedLinkError ule) {
+            System.err.println("Could not load AddModuleExportsAndOpensTest library");
+            System.err.println("java.library.path: "
+                + System.getProperty("java.library.path"));
+            throw ule;
+        }
+    }
+
+    native static int check(Module baseModule, Module thisModule);
+
+    public static void main(String args[]) {
+        Module baseModule = Object.class.getModule();
+        Module thisModule = AddModuleExportsAndOpensTest.class.getClassLoader().getUnnamedModule();
+        int status = check(baseModule, thisModule);
+        if (status != 0) {
+            throw new RuntimeException("Non-zero status returned from the agent: " + status);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/AddModuleExportsAndOpens/libAddModuleExportsAndOpensTest.c	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "jvmti.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_ARG
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG(x, y) y
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG(x,y) x, y
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+#define TranslateError(err) "JVMTI error"
+
+#define PASSED 0
+#define FAILED 2
+
+static const char *EXC_CNAME = "java/lang/Exception";
+static const char* MOD_CNAME = "Ljava/lang/reflect/Module;";
+
+static jvmtiEnv *jvmti = NULL;
+static jint result = PASSED;
+
+static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
+
+JNIEXPORT
+jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+    return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
+    return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
+    return JNI_VERSION_1_8;
+}
+
+static
+jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
+    jint res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
+                                        JVMTI_VERSION_9);
+    if (res != JNI_OK || jvmti == NULL) {
+        printf("    Error: wrong result of a valid call to GetEnv!\n");
+        return JNI_ERR;
+    }
+
+    return JNI_OK;
+}
+
+static
+jint throw_exc(JNIEnv *env, char *msg) {
+    jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
+
+    if (exc_class == NULL) {
+        printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
+        return -1;
+    }
+    return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
+}
+
+static
+jclass jlrM(JNIEnv *env) {
+    jclass cls = NULL;
+
+    cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME));
+    if (cls == NULL) {
+        printf("    Error in JNI FindClass: %s\n", MOD_CNAME);
+    }
+    return cls;
+}
+
+jmethodID
+get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) {
+    jmethodID method = NULL;
+
+    method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig);
+    if (method == NULL) {
+        printf("    Error in JNI GetMethodID %s with signature %s", name, sig);
+    }
+    return method;
+}
+
+static
+jboolean is_exported(JNIEnv *env, jobject module, const char* pkg, jboolean open) {
+    static jmethodID mIsExported = NULL;
+    jstring jstr = NULL;
+    jboolean res = JNI_FALSE;
+
+    if (mIsExported == NULL) {
+        const char* sign = "(Ljava/lang/String;)Z";
+        const char* name = open ? "isOpen" : "isExported";
+        mIsExported = get_method(env, jlrM(env), name, sign);
+    }
+    jstr = JNI_ENV_PTR(env)->NewStringUTF(JNI_ENV_ARG(env, pkg));
+    res = JNI_ENV_PTR(env)->CallBooleanMethod(JNI_ENV_ARG(env, module),
+                                              mIsExported, jstr);
+    return res;
+}
+
+static
+jboolean is_exported_to(JNIEnv *env, jobject module, const char* pkg, jobject to_module,
+                        jboolean open) {
+    static jmethodID mIsExportedTo = NULL;
+    jstring jstr = NULL;
+    jboolean res = JNI_FALSE;
+
+    if (mIsExportedTo == NULL) {
+        const char* sign = "(Ljava/lang/String;Ljava/lang/reflect/Module;)Z";
+        const char* name = open ? "isOpen" : "isExported";
+        mIsExportedTo = get_method(env, jlrM(env), name, sign);
+    }
+    jstr = JNI_ENV_PTR(env)->NewStringUTF(JNI_ENV_ARG(env, pkg));
+    res = JNI_ENV_PTR(env)->CallBooleanMethod(JNI_ENV_ARG(env, module),
+                                              mIsExportedTo, jstr, to_module);
+    return res;
+}
+
+static
+jvmtiError add_module_exports(jobject baseModule, const char* pkg, jobject thisModule,
+                              jboolean open) {
+    jvmtiError err = JVMTI_ERROR_NONE;
+    if (open) {
+        err = (*jvmti)->AddModuleOpens(jvmti, baseModule, pkg, thisModule);
+    } else {
+        err = (*jvmti)->AddModuleExports(jvmti, baseModule, pkg, thisModule);
+    }
+    return err;
+}
+
+static
+jint check_add_module_exports(JNIEnv *env,
+                              jclass  cls,
+                              jobject baseModule,
+                              jobject thisModule,
+                              jboolean open) {
+    static char strbuf[128] = { '\0' };
+    jvmtiError err = JVMTI_ERROR_NONE;
+    const char* pkg = open ? "jdk.internal.math"
+                           : "jdk.internal.misc";
+    const char* bad_pkg = "my.bad.pkg";
+    const char* jvmti_fn = open ? "AddModuleOpens"
+                                : "AddModuleExports";
+    jboolean exported = JNI_FALSE;
+
+    // Export from NULL module
+    printf("Check #N1:\n");
+    err = add_module_exports(NULL, pkg, thisModule, open);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#N1: jvmtiError from %s: %d\n", jvmti_fn, err);
+        throw_exc(env, "Check #N1: failed to return JVMTI_ERROR_NULL_POINTER for module==NULL");
+        return FAILED;
+    }
+
+    // Export NULL package
+    printf("Check #N2:\n");
+    err = add_module_exports(baseModule, NULL, thisModule, open);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#N2: jvmtiError from %s: %d\n", jvmti_fn, err);
+        throw_exc(env, "Check #N2: failed to return JVMTI_ERROR_NULL_POINTER for pkg==NULL");
+        return FAILED;
+    }
+
+    // Export to NULL module
+    printf("Check #N3:\n");
+    err = add_module_exports(baseModule, pkg, NULL, open);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#N3: jvmtiError from %s: %d\n", jvmti_fn, err);
+        throw_exc(env, "Check #N3: failed to return JVMTI_ERROR_NULL_POINTER for to_module==NULL");
+        return FAILED;
+    }
+
+    // Export a bad package
+    printf("Check #I0:\n");
+    err = add_module_exports(baseModule, bad_pkg, thisModule, open);
+    if (err != JVMTI_ERROR_ILLEGAL_ARGUMENT) {
+        printf("#I0: jvmtiError from %s: %d\n", jvmti_fn, err);
+        throw_exc(env, "Check #I0: did not get expected JVMTI_ERROR_ILLEGAL_ARGUMENT for invalid package");
+        return FAILED;
+    }
+
+    // Export from invalid module (cls)
+    printf("Check #I1:\n");
+    err = add_module_exports((jobject)cls, pkg, thisModule, open);
+    if (err != JVMTI_ERROR_INVALID_MODULE) {
+        printf("#I1: jvmtiError from %s: %d\n", jvmti_fn, err);
+        throw_exc(env, "Check #I1: did not get expected JVMTI_ERROR_INVALID_MODULE for invalid module");
+        return FAILED;
+    }
+
+    // Export to invalid module (cls)
+    printf("Check #I2:\n");
+    err = add_module_exports(baseModule, pkg, (jobject)cls, open);
+    if (err != JVMTI_ERROR_INVALID_MODULE) {
+        printf("#I2: jvmtiError from %s: %d\n", jvmti_fn, err);
+        throw_exc(env, "Check #I2: did not get expected JVMTI_ERROR_INVALID_MODULE for invalid to_module");
+        return FAILED;
+    }
+
+    // Check the pkg is not exported from baseModule to thisModule
+    printf("Check #C0:\n");
+    exported = is_exported_to(env, baseModule, pkg, thisModule, open);
+    if (exported != JNI_FALSE) {
+        sprintf(strbuf, "Check #C0: unexpected export of %s from base to this", pkg);
+        throw_exc(env, strbuf);
+        return FAILED;
+    }
+
+    // Add export of the pkg from baseModule to thisModule
+    printf("Check #C1:\n");
+    err = add_module_exports(baseModule, pkg, thisModule, open);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("#C1: jvmtiError from %s: %d\n", jvmti_fn, err);
+        sprintf(strbuf, "Check #C1: error in add export of %s from base to this", pkg);
+        throw_exc(env, strbuf);
+        return FAILED;
+    }
+
+    // Check the pkg is exported from baseModule to thisModule
+    printf("Check #C2:\n");
+    exported = is_exported_to(env, baseModule, pkg, thisModule, open);
+    if (exported == JNI_FALSE) {
+        sprintf(strbuf, "Check #C2: failed to export %s from base to this", pkg);
+        throw_exc(env, strbuf);
+        return FAILED;
+    }
+
+    // Check the pkg is not exported to all modules
+    printf("Check #C3:\n");
+    exported = is_exported(env, baseModule, pkg, open);
+    if (exported != JNI_FALSE) {
+        sprintf(strbuf, "Check #C3: unexpected export of %s from base to all modules", pkg);
+        throw_exc(env, strbuf);
+        return FAILED;
+    }
+    return PASSED;
+}
+
+JNIEXPORT jint JNICALL
+Java_MyPackage_AddModuleExportsAndOpensTest_check(JNIEnv *env,
+                                                  jclass cls,
+                                                  jobject baseModule,
+                                                  jobject thisModule) {
+    if (jvmti == NULL) {
+        throw_exc(env, "JVMTI client was not properly loaded!\n");
+        return FAILED;
+    }
+
+    printf("\n*** Checks for JVMTI AddModuleExports ***\n\n");
+    result = check_add_module_exports(env, cls, baseModule, thisModule, JNI_FALSE);
+    if (result != PASSED) {
+        return result;
+    }
+
+    printf("\n*** Checks for JVMTI AddModuleOpens ***\n\n");
+    result = check_add_module_exports(env, cls, baseModule, thisModule, JNI_TRUE);
+    if (result != PASSED) {
+        return result;
+    }
+    return result;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/AddModuleReads/MyPackage/AddModuleReadsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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 MyPackage;
+
+/**
+ * @test
+ * @summary Verifies the JVMTI AddModuleReads API
+ * @compile AddModuleReadsTest.java
+ * @run main/othervm/native -agentlib:AddModuleReadsTest MyPackage.AddModuleReadsTest
+ */
+
+import java.io.PrintStream;
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Module;
+
+public class AddModuleReadsTest {
+
+    static {
+        try {
+            System.loadLibrary("AddModuleReadsTest");
+        } catch (UnsatisfiedLinkError ule) {
+            System.err.println("Could not load AddModuleReadsTest library");
+            System.err.println("java.library.path: "
+                + System.getProperty("java.library.path"));
+            throw ule;
+        }
+    }
+
+    native static int check(Module unnamed, Module base, Module instrument);
+
+    public static void main(String args[]) {
+        Module unnamed = AddModuleReadsTest.class.getClassLoader().getUnnamedModule();
+        Module base = Object.class.getModule();
+        Module instrument = Instrumentation.class.getModule();
+        int status = check(unnamed, base, instrument);
+        if (status != 0) {
+            throw new RuntimeException("Non-zero status returned from the agent: " + status);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/AddModuleReads/libAddModuleReadsTest.c	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "jvmti.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_ARG
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG(x, y) y
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG(x,y) x, y
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+#define TranslateError(err) "JVMTI error"
+
+#define PASSED 0
+#define FAILED 2
+
+static const char *EXC_CNAME = "java/lang/Exception";
+static const char* MOD_CNAME = "Ljava/lang/reflect/Module;";
+
+static jvmtiEnv *jvmti = NULL;
+static jint result = PASSED;
+
+static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
+
+JNIEXPORT
+jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+    return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
+    return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
+    return JNI_VERSION_1_8;
+}
+
+static
+jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
+    jint res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
+                                        JVMTI_VERSION_9);
+    if (res != JNI_OK || jvmti == NULL) {
+        printf("    Error: wrong result of a valid call to GetEnv!\n");
+        return JNI_ERR;
+    }
+    return JNI_OK;
+}
+
+static
+jint throw_exc(JNIEnv *env, char *msg) {
+    jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
+
+    if (exc_class == NULL) {
+        printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
+        return -1;
+    }
+    return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
+}
+
+static
+jclass jlrM(JNIEnv *env) {
+    jclass cls = NULL;
+
+    cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME));
+    if (cls == NULL) {
+        printf("    Error in JNI FindClass: %s\n", MOD_CNAME);
+    }
+    return cls;
+}
+
+jmethodID
+get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) {
+    jmethodID method = NULL;
+
+    method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig);
+    if (method == NULL) {
+        printf("    Error in JNI GetMethodID %s with signature %s", name, sig);
+    }
+    return method;
+}
+
+static
+jboolean can_module_read(JNIEnv *env, jobject module, jobject to_module) {
+    static jmethodID mCanRead = NULL;
+    jboolean res = JNI_FALSE;
+
+    if (mCanRead == NULL) {
+        const char* sign = "(Ljava/lang/reflect/Module;)Z";
+        mCanRead = get_method(env, jlrM(env), "canRead", sign);
+    }
+    res = JNI_ENV_PTR(env)->CallBooleanMethod(JNI_ENV_ARG(env, module),
+                                              mCanRead, to_module);
+    return res;
+}
+
+static
+jint check_add_module_reads(JNIEnv *env,
+                            jclass  cls,
+                            jobject unnamedModule,
+                            jobject baseModule,
+                            jobject instrModule) {
+    jvmtiError err = JVMTI_ERROR_NONE;
+    jboolean can = JNI_FALSE;
+
+    // Add an invalid read edge from NULL module
+    printf("Check #N1:\n");
+    err = (*jvmti)->AddModuleReads(jvmti, NULL, baseModule);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#N1: jvmtiError from AddModuleReads: %d\n", err);
+        throw_exc(env, "Check #N1: failed to return JVMTI_ERROR_NULL_POINTER for module==NULL");
+        return FAILED;
+    }
+
+    // Add an invalid read edge to NULL module
+    printf("Check #N2:\n");
+    err = (*jvmti)->AddModuleReads(jvmti, baseModule, NULL);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#N2: jvmtiError from AddModuleReads: %d\n", err);
+        throw_exc(env, "Check #N2: failed to return JVMTI_ERROR_NULL_POINTER for to_module==NULL");
+        return FAILED;
+    }
+
+    // Add an invalid read edge from invalid module (cls)
+    printf("Check #I1:\n");
+    err = (*jvmti)->AddModuleReads(jvmti, cls, baseModule);
+    if (err != JVMTI_ERROR_INVALID_MODULE) {
+        printf("#I1: jvmtiError from AddModuleReads: %d\n", err);
+        throw_exc(env, "Check #I1: failed to return JVMTI_ERROR_INVALID_MODULE for module==cls");
+        return FAILED;
+    }
+
+    // Add an invalid read edge to invalid module (cls)
+    printf("Check #I2:\n");
+    err = (*jvmti)->AddModuleReads(jvmti, baseModule, cls);
+    if (err != JVMTI_ERROR_INVALID_MODULE) {
+        printf("#I2: jvmtiError from AddModuleReads: %d\n", err);
+        throw_exc(env, "Check #I2: failed to return JVMTI_ERROR_INVALID_MODULE for to_module==cls");
+        return FAILED;
+    }
+
+    // Check the edge baseModule->instrModule is absent
+    printf("Check #C0:\n");
+    can = can_module_read(env, baseModule, instrModule);
+    if (can != JNI_FALSE) {
+        throw_exc(env, "Check #C0: read edge from base to instr is unexpected");
+        return FAILED;
+    }
+
+    // Add read edge baseModule->instrModule
+    printf("Check #C1:\n");
+    err = (*jvmti)->AddModuleReads(jvmti, baseModule, instrModule);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("#C1: jvmtiError from AddModuleReads: %d\n", err);
+        throw_exc(env, "Check #C1: error in add reads from base to instr");
+        return FAILED;
+    }
+
+    // Check the read edge baseModule->instrModule is present now
+    printf("Check #C2:\n");
+    can = can_module_read(env, baseModule, instrModule);
+    if (can == JNI_FALSE) {
+        throw_exc(env, "Check #C2: failed to add reads from base to instr");
+        return FAILED;
+    }
+
+    // Check the read edge baseModule->unnamedModule is absent
+    printf("Check #C3:\n");
+    can = can_module_read(env, baseModule, unnamedModule);
+    if (can != JNI_FALSE) {
+        throw_exc(env, "Check #C3: got unexpected read edge from base to unnamed");
+        return FAILED;
+    }
+
+    // Add read edge baseModule->unnamedModule
+    printf("Check #C4:\n");
+    err = (*jvmti)->AddModuleReads(jvmti, baseModule, unnamedModule);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("#C4: jvmtiError from AddModuleReads: %d\n", err);
+        throw_exc(env, "Check #C4: failed to ignore adding read edge from base to unnamed");
+        return FAILED;
+    }
+
+    // Check the read edge baseModule->unnamedModule is present now
+    printf("Check #C5:\n");
+    can = can_module_read(env, baseModule, unnamedModule);
+    if (can == JNI_FALSE) {
+        throw_exc(env, "Check #C5: did not get expected read edge from base to unnamed");
+        return FAILED;
+    }
+
+    // Check the read edge unnamedModule->instrModule is absent
+    printf("Check #C6:\n");
+    can = can_module_read(env, unnamedModule, instrModule);
+    if (can == JNI_FALSE) {
+        throw_exc(env, "Check #C6: did not get expected read edge from unnamed to instr");
+        return FAILED;
+    }
+
+    // Add read edge unnamedModule->instrModule
+    printf("Check #C7:\n");
+    err = (*jvmti)->AddModuleReads(jvmti, unnamedModule, instrModule);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("#C7: jvmtiError from AddModuleReads: %d\n", err);
+        throw_exc(env, "Check #C7: failed to ignore adding read edge from unnamed to instr");
+        return FAILED;
+    }
+    return PASSED;
+}
+
+JNIEXPORT jint JNICALL
+Java_MyPackage_AddModuleReadsTest_check(JNIEnv *env,
+                                        jclass cls,
+                                        jobject unnamedModule,
+                                        jobject baseModule,
+                                        jobject instrModule) {
+    if (jvmti == NULL) {
+        throw_exc(env, "JVMTI client was not properly loaded!\n");
+        return FAILED;
+    }
+
+    printf("\n*** Checks for JVMTI AddModuleReads ***\n\n");
+    result = check_add_module_reads(env, cls, unnamedModule, baseModule, instrModule);
+    if (result != PASSED) {
+        return result;
+    }
+    return result;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/AddModuleUsesAndProvides/MyPackage/AddModuleUsesAndProvidesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,84 @@
+/*
+ * 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 MyPackage;
+
+/**
+ * @test
+ * @summary Basic test for JVMTI AddModuleUses and AddModuleProvides
+ * @build java.base/java.lang.TestProvider
+ *        java.base/jdk.internal.test.TestProviderImpl
+ * @compile AddModuleUsesAndProvidesTest.java
+ * @run main/othervm/native -agentlib:AddModuleUsesAndProvidesTest MyPackage.AddModuleUsesAndProvidesTest
+ */
+
+import java.io.PrintStream;
+import java.lang.TestProvider;
+import java.lang.reflect.Module;
+
+public class AddModuleUsesAndProvidesTest {
+
+    static {
+        try {
+            System.loadLibrary("AddModuleUsesAndProvidesTest");
+        } catch (UnsatisfiedLinkError ule) {
+            System.err.println("Could not load AddModuleUsesAndProvidesTest library");
+            System.err.println("java.library.path: "
+                + System.getProperty("java.library.path"));
+            throw ule;
+        }
+    }
+
+    native static int checkUses(Module baseModule, Class<?> service);
+    native static int checkProvides(Module baseModule, Class<?> service, Class<?> serviceImpl);
+
+    public static void main(String args[]) throws Exception {
+        Module baseModule = Object.class.getModule();
+        Class<?> service = TestProvider.class;
+        Class<?> serviceImpl = Class.forName("jdk.internal.test.TestProviderImpl");
+
+        System.out.println("\n*** Checks for JVMTI AddModuleUses ***\n");
+
+        int status = checkUses(baseModule, service);
+        if (status != 0) {
+            throw new RuntimeException("Non-zero status returned from the agent: " + status);
+        }
+
+        System.out.println("\n*** Checks for JVMTI AddModuleProvides ***\n");
+
+        System.out.println("Check #PC1:");
+        if (TestProvider.providers().iterator().hasNext()) {
+            throw new RuntimeException("Check #PC1: Unexpectedly service is provided");
+        }
+
+        status = checkProvides(baseModule, service, serviceImpl);
+        if (status != 0) {
+            throw new RuntimeException("Non-zero status returned from the agent: " + status);
+        }
+
+        System.out.println("Check #PC3:");
+        if (!TestProvider.providers().iterator().hasNext()) {
+            throw new RuntimeException("Check #PC3: Unexpectedly service is not provided");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/AddModuleUsesAndProvides/MyPackage/java.base/java/lang/TestProvider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package java.lang;
+
+import java.util.ServiceLoader;
+
+public interface TestProvider {
+    public static Iterable<TestProvider> providers() {
+        return ServiceLoader.load(TestProvider.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/AddModuleUsesAndProvides/MyPackage/java.base/jdk/internal/test/TestProviderImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package jdk.internal.test;
+
+import java.lang.TestProvider;
+
+public class TestProviderImpl implements TestProvider {
+    public TestProviderImpl() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "jvmti.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_ARG
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG(x, y) y
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG(x,y) x, y
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+#define TranslateError(err) "JVMTI error"
+
+#define PASSED 0
+#define FAILED 2
+
+static const char *EXC_CNAME = "java/lang/Exception";
+static const char* MOD_CNAME = "Ljava/lang/reflect/Module;";
+
+static jvmtiEnv *jvmti = NULL;
+static jint result = PASSED;
+
+static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
+
+JNIEXPORT
+jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+    return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
+    return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
+    return JNI_VERSION_1_8;
+}
+
+static
+jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
+    jint res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
+                                        JVMTI_VERSION_9);
+    if (res != JNI_OK || jvmti == NULL) {
+        printf("    Error: wrong result of a valid call to GetEnv!\n");
+        return JNI_ERR;
+    }
+
+    return JNI_OK;
+}
+
+static
+jint throw_exc(JNIEnv *env, char *msg) {
+    jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
+
+    if (exc_class == NULL) {
+        printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
+        return -1;
+    }
+    return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
+}
+
+static
+jclass jlrM(JNIEnv *env) {
+    jclass cls = NULL;
+
+    cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME));
+    if (cls == NULL) {
+        printf("    Error in JNI FindClass: %s\n", MOD_CNAME);
+    }
+    return cls;
+}
+
+jmethodID
+get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) {
+    jmethodID method = NULL;
+
+    method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig);
+    if (method == NULL) {
+        printf("    Error in JNI GetMethodID %s with signature %s", name, sig);
+    }
+    return method;
+}
+
+static
+jboolean can_use_service(JNIEnv *env, jobject module, jclass service) {
+    static jmethodID mCanUse = NULL;
+    jboolean res = JNI_FALSE;
+
+    if (mCanUse == NULL) {
+        const char* sign = "(Ljava/lang/Class;)Z";
+        mCanUse = get_method(env, jlrM(env), "canUse", sign);
+    }
+    res = JNI_ENV_PTR(env)->CallBooleanMethod(JNI_ENV_ARG(env, module),
+                                              mCanUse, service);
+    return res;
+}
+
+JNIEXPORT jint JNICALL
+Java_MyPackage_AddModuleUsesAndProvidesTest_checkUses(JNIEnv *env,
+                                                      jclass  cls,
+                                                      jobject baseModule,
+                                                      jclass  service) {
+    jvmtiError err = JVMTI_ERROR_NONE;
+    jboolean used = JNI_FALSE;
+
+    // Add a service to use to NULL module
+    printf("Check #UN1:\n");
+    err = (*jvmti)->AddModuleUses(jvmti, NULL, service);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#UN1: jvmtiError from AddModuleUses: %d\n", err);
+        throw_exc(env, "Check #UN1: failed to return JVMTI_ERROR_NULL_POINTER for module==NULL");
+        return FAILED;
+    }
+
+    // Add NULL service to use to baseModule
+    printf("Check #UN2:\n");
+    err = (*jvmti)->AddModuleUses(jvmti, baseModule, NULL);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#UN2: jvmtiError from AddModuleUses: %d\n", err);
+        throw_exc(env, "Check #UN2: failed to return JVMTI_ERROR_NULL_POINTER for service==NULL");
+        return FAILED;
+    }
+
+    // Add service to use to invalid module (cls)
+    printf("Check #UI1:\n");
+    err = (*jvmti)->AddModuleUses(jvmti, (jobject)cls, service);
+    if (err != JVMTI_ERROR_INVALID_MODULE) {
+        printf("#UI1: jvmtiError from AddModuleUses: %d\n", err);
+        throw_exc(env, "Check #UI1: did not get expected JVMTI_ERROR_INVALID_MODULE for invalid module");
+        return FAILED;
+    }
+
+    // Add invalid service (thisModule) to use to baseModule
+    printf("Check #UI2:\n");
+    err = (*jvmti)->AddModuleUses(jvmti, baseModule, baseModule);
+    if (err != JVMTI_ERROR_INVALID_CLASS) {
+        printf("#UI2: jvmtiError from AddModuleUses: %d\n", err);
+        throw_exc(env, "Check #UI2: did not get expected JVMTI_ERROR_INVALID_CLASS for invalid service");
+        return FAILED;
+    }
+
+    // Check if the service can not be used
+    printf("Check #UC1:\n");
+    used = can_use_service(env, baseModule, service);
+    if (used != JNI_FALSE) {
+        throw_exc(env, "Check #UC1: unexpected use of service");
+        return FAILED;
+    }
+
+    // Add uses of a correct service
+    printf("Check #UC2:\n");
+    err = (*jvmti)->AddModuleUses(jvmti, baseModule, service);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("#UC2: jvmtiError from AddModuleUses: %d\n", err);
+        throw_exc(env, "Check #UC2: got unexpected JVMTI error");
+        return FAILED;
+    }
+
+    // Check if the service can not be used
+    printf("Check #UC3:\n");
+    used = can_use_service(env, baseModule, service);
+    if (used == JNI_FALSE) {
+        throw_exc(env, "Check #UC3: service can not be used unexpectedly");
+        return FAILED;
+    }
+    fflush(0);
+    return PASSED;
+}
+
+JNIEXPORT jint JNICALL
+Java_MyPackage_AddModuleUsesAndProvidesTest_checkProvides(JNIEnv *env,
+                                                          jclass  cls,
+                                                          jobject baseModule,
+                                                          jclass  service,
+                                                          jclass  serviceImpl) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+   jboolean provided = JNI_FALSE;
+
+    // Add provides to NULL module
+    printf("Check #PN1:\n");
+    err = (*jvmti)->AddModuleProvides(jvmti, NULL, service, serviceImpl);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#PN1: jvmtiError from AddModuleProvides: %d\n", err);
+        throw_exc(env, "Check #PN1: failed to return JVMTI_ERROR_NULL_POINTER for module==NULL");
+        return FAILED;
+    }
+
+    // Add provides with NULL service
+    printf("Check #PN2:\n");
+    err = (*jvmti)->AddModuleProvides(jvmti, baseModule, NULL, serviceImpl);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#PN2: jvmtiError from AddModuleProvides: %d\n", err);
+        throw_exc(env, "Check #PN2: failed to return JVMTI_ERROR_NULL_POINTER for service==NULL");
+        return FAILED;
+    }
+
+    // Add provides with NULL serviceImpl
+    printf("Check #PN3:\n");
+    err = (*jvmti)->AddModuleProvides(jvmti, baseModule, service, NULL);
+    if (err != JVMTI_ERROR_NULL_POINTER) {
+        printf("#PN3: jvmtiError from AddModuleProvides: %d\n", err);
+        throw_exc(env, "Check #PN3: failed to return JVMTI_ERROR_NULL_POINTER for serviceImpl==NULL");
+        return FAILED;
+    }
+
+    // Add provides to invalid module (cls)
+    printf("Check #PI1:\n");
+    err = (*jvmti)->AddModuleProvides(jvmti, (jobject)cls, service, serviceImpl);
+    if (err != JVMTI_ERROR_INVALID_MODULE) {
+        printf("#PI1: jvmtiError from AddModuleProvides: %d\n", err);
+        throw_exc(env, "Check #PI1: did not get expected JVMTI_ERROR_INVALID_MODULE for invalid module");
+        return FAILED;
+    }
+
+    // Add provides with invalid service (baseModule)
+    printf("Check #PI2:\n");
+    err = (*jvmti)->AddModuleProvides(jvmti, baseModule, baseModule, serviceImpl);
+    if (err != JVMTI_ERROR_INVALID_CLASS) {
+        printf("#PI2: jvmtiError from AddModuleProvides: %d\n", err);
+        throw_exc(env, "Check #PI2: did not get expected JVMTI_ERROR_INVALID_CLASS for invalid service");
+        return FAILED;
+    }
+
+    // Add provides with invalid serviceImpl (baseModule)
+    printf("Check #PI3:\n");
+    err = (*jvmti)->AddModuleProvides(jvmti, baseModule, service, baseModule);
+    if (err != JVMTI_ERROR_INVALID_CLASS) {
+        printf("#PI3: jvmtiError from AddModuleProvides: %d\n", err);
+        throw_exc(env, "Check #PI3: did not get expected JVMTI_ERROR_INVALID_CLASS for invalid serviceImpl");
+        return FAILED;
+    }
+
+    // Add provides to baseModule with correct service and serviceImpl
+    printf("Check #PC2:\n");
+    err = (*jvmti)->AddModuleProvides(jvmti, baseModule, service, serviceImpl);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("#PC2: jvmtiError from AddModuleExports: %d\n", err);
+        throw_exc(env, "Check #PC2: error in add provides to baseModule with correct service and serviceImpl");
+        return FAILED;
+    }
+    fflush(0);
+    return PASSED;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- a/hotspot/test/serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -72,8 +72,7 @@
 
         // Load a new named module
         ModuleDescriptor descriptor
-                = new ModuleDescriptor.Builder(MY_MODULE_NAME)
-                .build();
+                = ModuleDescriptor.module(MY_MODULE_NAME).build();
         ModuleFinder finder = finderOf(descriptor);
         ClassLoader loader = new ClassLoader() {};
         Configuration parent = Layer.boot().configuration();
--- a/hotspot/test/serviceability/sa/TestInstanceKlassSize.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/serviceability/sa/TestInstanceKlassSize.java	Wed Jul 05 22:32:06 2017 +0200
@@ -46,6 +46,7 @@
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
  * @compile -XDignore.symbol.file=true
+ *          --add-modules=jdk.hotspot.agent
  *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED
  *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED
  *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
--- a/hotspot/test/serviceability/sa/TestInstanceKlassSizeForInterface.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/hotspot/test/serviceability/sa/TestInstanceKlassSizeForInterface.java	Wed Jul 05 22:32:06 2017 +0200
@@ -39,6 +39,7 @@
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
  * @compile -XDignore.symbol.file=true
+ *          --add-modules=jdk.hotspot.agent
  *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED
  *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED
  *          --add-exports=jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED
--- a/jdk/.hgignore	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/.hgignore	Wed Jul 05 22:32:06 2017 +0200
@@ -5,7 +5,6 @@
 /nbproject/private/
 ^make/netbeans/.*/build/
 ^make/netbeans/.*/dist/
-^.hgtip
 .DS_Store
 .*/JTreport/.*
 .*/JTwork/.*
--- a/jdk/.hgtags	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/.hgtags	Wed Jul 05 22:32:06 2017 +0200
@@ -389,3 +389,4 @@
 efa71dc820eb8bd5a6c9f2f66f39c383ac3ee99d jdk-9+144
 99b7853cfbd8227c4441de4b6119c10742556840 jdk-9+145
 6e4ff59afb5d0adf21a72c4ff534326594a99e5d jdk-9+146
+c41140100bf1e5c10c7b8f3bde91c16eff7485f5 jdk-9+147
--- a/jdk/make/data/jdwp/jdwp.spec	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/data/jdwp/jdwp.spec	Wed Jul 05 22:32:06 2017 +0200
@@ -2709,22 +2709,6 @@
             (Error VM_DEAD)
         )
     )
-    (Command CanRead=3
-        "Returns true if this module can read the source module; false otherwise."
-        "<p>Since JDWP version 9."
-        (Out
-            (moduleID module "This module.")
-            (moduleID sourceModule "The source module.")
-        )
-        (Reply
-            (boolean canRead  "true if this module can read the source module; false otherwise.")
-        )
-        (ErrorSet
-            (Error INVALID_MODULE  "This module or sourceModule is not the ID of a module.")
-            (Error NOT_IMPLEMENTED)
-            (Error VM_DEAD)
-        )
-    )
 )
 (CommandSet Event=64
     (Command Composite=100
--- a/jdk/make/gensrc/GensrcMisc.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/gensrc/GensrcMisc.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -108,3 +108,19 @@
 endif
 
 ################################################################################
+# Create the javax/crypto/JceSecurity.class, using the build default.
+#
+ifeq ($(UNLIMITED_CRYPTO), true)
+    JCE_DEFAULT_POLICY = unlimited
+else
+    JCE_DEFAULT_POLICY = limited
+endif
+
+$(eval $(call SetupTextFileProcessing, BUILD_JCESECURITY_JAVA, \
+    SOURCE_FILES := $(JDK_TOPDIR)/src/java.base/share/classes/javax/crypto/JceSecurity.java.template, \
+    OUTPUT_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/javax/crypto/JceSecurity.java, \
+    REPLACEMENTS := \
+        @@JCE_DEFAULT_POLICY@@ => $(JCE_DEFAULT_POLICY), \
+))
+
+GENSRC_JAVA_BASE += $(BUILD_JCESECURITY_JAVA)
--- a/jdk/make/launcher/Launcher-jdk.jconsole.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/launcher/Launcher-jdk.jconsole.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,8 @@
 
 $(eval $(call SetupBuildLauncher, jconsole, \
     MAIN_CLASS := sun.tools.jconsole.JConsole, \
-    JAVA_ARGS := -Djconsole.showOutputViewer, \
+    JAVA_ARGS := --add-opens java.base/java.io=jdk.jconsole \
+		 -Djconsole.showOutputViewer, \
     CFLAGS_windows := -DJAVAW, \
     LIBS_windows := user32.lib, \
 ))
--- a/jdk/make/lib/Awt2dLibraries.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/lib/Awt2dLibraries.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -287,9 +287,8 @@
         $(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
         $(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/utility \
         $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \
-        $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
-        $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/opengl \
-        $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/x11 \
+        $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d \
+        $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d \
         $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \
         #
 
@@ -396,7 +395,7 @@
 
 ifeq ($(USE_EXTERNAL_LCMS), true)
   # If we're using an external library, we'll just need the wrapper part.
-  # By including it explicitely, all other files will be excluded.
+  # By including it explicitly, all other files will be excluded.
   BUILD_LIBLCMS_INCLUDE_FILES := LCMS.c
 else
   BUILD_LIBLCMS_INCLUDE_FILES :=
@@ -516,24 +515,25 @@
 
   LIBAWT_HEADLESS_DIRS := $(JDK_TOPDIR)/src/java.desktop/unix/native/libawt_headless/awt \
       $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \
-      $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/opengl \
-      $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/x11 \
-      $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
+      $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d \
+      $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d \
       $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \
       #
 
   LIBAWT_HEADLESS_EXCLUDES := medialib
   LIBAWT_HEADLESS_CFLAGS := -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \
       $(addprefix -I, $(LIBAWT_HEADLESS_DIRS)) \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d \
+      -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libawt/java2d \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/loops \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/pipe \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image \
-      -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libawt/java2d \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/font \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
       -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/font \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
+      -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/opengl \
       -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libsunwjdga/ \
       $(LIBJAVA_HEADER_FLAGS) \
       #
@@ -862,7 +862,7 @@
 
   ifeq ($(OPENJDK_TARGET_OS), windows)
     LIBSPLASHSCREEN_DIRS += $(JDK_TOPDIR)/src/java.desktop/windows/native/common/awt/systemscale
-  endif	
+  endif
   LIBSPLASHSCREEN_CFLAGS += -DSPLASHSCREEN -DPNG_NO_MMX_CODE -DPNG_ARM_NEON_OPT=0 \
       $(addprefix -I, $(LIBSPLASHSCREEN_DIRS)) \
       $(LIBJAVA_HEADER_FLAGS) \
@@ -952,26 +952,27 @@
       $(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt \
       $(JDK_TOPDIR)/src/java.desktop/unix/native/common/awt \
       $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \
-      $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
+      $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d \
       #
 
   LIBAWT_LWAWT_CFLAGS := \
       $(addprefix -I, $(LIBAWT_LWAWT_DIRS)) \
       -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \
-      -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/include \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/include \
-      -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl \
       -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/awt \
       -I$(JDK_TOPDIR)/src/java.desktop/unix/native/libawt_xawt/awt \
       -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/font \
+      -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
+      -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/include \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/include \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d \
       -I$(JDK_TOPDIR)/src/java.desktop/unix/native/libawt/java2d \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libmlib_image/ \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/loops \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/pipe \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libmlib_image/ \
       -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libosxapp \
       $(LIBJAVA_HEADER_FLAGS) \
       #
--- a/jdk/make/lib/CoreLibraries.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/lib/CoreLibraries.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -33,10 +33,22 @@
 # libfdlibm is statically linked with libjava below and not delivered into the
 # product on its own.
 
-BUILD_LIBFDLIBM_OPTIMIZATION := HIGH
+BUILD_LIBFDLIBM_OPTIMIZATION := NONE
+
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+  BUILD_LIBFDLIBM_OPTIMIZATION := HIGH
+endif
 
-ifneq ($(OPENJDK_TARGET_OS), solaris)
-  BUILD_LIBFDLIBM_OPTIMIZATION := NONE
+ifeq ($(OPENJDK_TARGET_OS), linux)
+  ifeq ($(OPENJDK_TARGET_CPU), ppc64)
+    BUILD_LIBFDLIBM_OPTIMIZATION := HIGH
+  else ifeq ($(OPENJDK_TARGET_CPU), ppc64le)
+    BUILD_LIBFDLIBM_OPTIMIZATION := HIGH
+  else ifeq ($(OPENJDK_TARGET_CPU), s390x)
+    BUILD_LIBFDLIBM_OPTIMIZATION := HIGH
+  else ifeq ($(OPENJDK_TARGET_CPU), aarch64)
+    BUILD_LIBFDLIBM_OPTIMIZATION := HIGH
+  endif
 endif
 
 LIBFDLIBM_SRC := $(JDK_TOPDIR)/src/java.base/share/native/libfdlibm
@@ -51,6 +63,10 @@
       CFLAGS := $(CFLAGS_JDKLIB) $(LIBFDLIBM_CFLAGS), \
       CFLAGS_windows_debug := -DLOGGING, \
       CFLAGS_aix := -qfloat=nomaf, \
+      CFLAGS_linux_ppc64 := -ffp-contract=off, \
+      CFLAGS_linux_ppc64le := -ffp-contract=off, \
+      CFLAGS_linux_s390x := -ffp-contract=off, \
+      CFLAGS_linux_aarch64 := -ffp-contract=off, \
       DISABLED_WARNINGS_gcc := sign-compare, \
       DISABLED_WARNINGS_microsoft := 4146 4244 4018, \
       ARFLAGS := $(ARFLAGS), \
--- a/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java	Wed Jul 05 22:32:06 2017 +0200
@@ -65,7 +65,7 @@
                     String mn = entry.getFileName().toString();
                     Optional<ModuleReference> omref = finder.find(mn);
                     if (omref.isPresent()) {
-                        Set<String> packages = omref.get().descriptor().conceals();
+                        Set<String> packages = omref.get().descriptor().packages();
                         addPackagesAttribute(mi, packages);
                     }
                 }
@@ -77,7 +77,7 @@
         byte[] bytes;
         try (InputStream in = Files.newInputStream(mi)) {
             ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
-            extender.conceals(packages);
+            extender.packages(packages);
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             extender.write(baos);
             bytes = baos.toByteArray();
--- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Wed Jul 05 22:32:06 2017 +0200
@@ -43,7 +43,7 @@
 import java.util.TreeSet;
 import java.util.function.Function;
 import java.util.stream.Collectors;
-import static java.lang.module.ModuleDescriptor.Requires.Modifier.PUBLIC;
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.TRANSITIVE;
 
 /**
  * Generate the DOT file for a module graph for each module in the JDK
@@ -172,14 +172,14 @@
             Graph<String> graph = gengraph(cf);
             descriptors.forEach(md -> {
                 String mn = md.name();
-                Set<String> requiresPublic = md.requires().stream()
-                        .filter(d -> d.modifiers().contains(PUBLIC))
+                Set<String> requiresTransitive = md.requires().stream()
+                        .filter(d -> d.modifiers().contains(TRANSITIVE))
                         .map(d -> d.name())
                         .collect(Collectors.toSet());
 
                 graph.adjacentNodes(mn).forEach(dn -> {
                     String attr = dn.equals("java.base") ? REQUIRES_BASE
-                            : (requiresPublic.contains(dn) ? REEXPORTS : REQUIRES);
+                            : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
                     int w = weightOf(mn, dn);
                     if (w > 1)
                         attr += "weight=" + w;
@@ -194,8 +194,8 @@
     /**
      * Returns a Graph of the given Configuration after transitive reduction.
      *
-     * Transitive reduction of requires public edge and requires edge have
-     * to be applied separately to prevent the requires public edges
+     * Transitive reduction of requires transitive edge and requires edge have
+     * to be applied separately to prevent the requires transitive edges
      * (e.g. U -> V) from being reduced by a path (U -> X -> Y -> V)
      * in which  V would not be re-exported from U.
      */
@@ -208,21 +208,21 @@
                     .map(ResolvedModule::name)
                     .forEach(target -> builder.addEdge(mn, target));
         }
-        Graph<String> rpg = requiresPublicGraph(cf);
+        Graph<String> rpg = requiresTransitiveGraph(cf);
         return builder.build().reduce(rpg);
     }
 
     /**
-     * Returns a Graph containing only requires public edges
+     * Returns a Graph containing only requires transitive edges
      * with transitive reduction.
      */
-    private Graph<String> requiresPublicGraph(Configuration cf) {
+    private Graph<String> requiresTransitiveGraph(Configuration cf) {
         Graph.Builder<String> builder = new Graph.Builder<>();
         for (ResolvedModule resolvedModule : cf.modules()) {
             ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
             String mn = descriptor.name();
             descriptor.requires().stream()
-                    .filter(d -> d.modifiers().contains(PUBLIC))
+                    .filter(d -> d.modifiers().contains(TRANSITIVE))
                     .map(d -> d.name())
                     .forEach(d -> builder.addEdge(mn, d));
         }
--- a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java	Wed Jul 05 22:32:06 2017 +0200
@@ -299,7 +299,7 @@
     static class HtmlDocument {
         final String title;
         final Map<String, ModuleSummary> modules;
-        boolean requiresPublicNote = false;
+        boolean requiresTransitiveNote = false;
         boolean aggregatorNote = false;
         boolean totalBytesNote = false;
         HtmlDocument(String title, Map<String, ModuleSummary> modules) {
@@ -510,16 +510,16 @@
             public String requiresColumn() {
                 StringBuilder sb = new StringBuilder();
                 sb.append(String.format("<td>"));
-                boolean footnote = requiresPublicNote;
+                boolean footnote = requiresTransitiveNote;
                 ms.descriptor().requires().stream()
                         .sorted(Comparator.comparing(Requires::name))
                         .forEach(r -> {
-                            boolean requiresPublic = r.modifiers().contains(Requires.Modifier.PUBLIC);
-                            Selector sel = requiresPublic ? REQUIRES_PUBLIC : REQUIRES;
+                            boolean requiresTransitive = r.modifiers().contains(Requires.Modifier.TRANSITIVE);
+                            Selector sel = requiresTransitive ? REQUIRES_PUBLIC : REQUIRES;
                             String req = String.format("<a class=\"%s\" href=\"#%s\">%s</a>",
                                                        sel, r.name(), r.name());
-                            if (!requiresPublicNote && requiresPublic) {
-                                requiresPublicNote = true;
+                            if (!requiresTransitiveNote && requiresTransitive) {
+                                requiresTransitiveNote = true;
                                 req += "<sup>*</sup>";
                             }
                             sb.append(req).append("\n").append("<br>");
@@ -534,8 +534,8 @@
                     sb.append("<br>");
                     sb.append("<i>+").append(indirectDeps).append(" transitive dependencies</i>");
                 }
-                if (footnote != requiresPublicNote) {
-                    sb.append("<br><br>").append("<i>* bold denotes requires public</i>");
+                if (footnote != requiresTransitiveNote) {
+                    sb.append("<br><br>").append("<i>* bold denotes requires transitive</i>");
                 }
                 sb.append("</td>");
                 return sb.toString();
@@ -558,11 +558,10 @@
                 ms.descriptor().uses().stream()
                         .sorted()
                         .forEach(s -> sb.append("uses ").append(s).append("<br>").append("\n"));
-                ms.descriptor().provides().entrySet().stream()
-                        .sorted(Map.Entry.comparingByKey())
-                        .flatMap(e -> e.getValue().providers().stream()
-                                .map(p -> String.format("provides %s<br>&nbsp;&nbsp;&nbsp;&nbsp;with %s",
-                                                        e.getKey(), p)))
+                ms.descriptor().provides().stream()
+                        .sorted(Comparator.comparing(Provides::service))
+                        .map(p -> String.format("provides %s<br>&nbsp;&nbsp;&nbsp;&nbsp;with %s",
+                                                p.service(), p.providers()))
                         .forEach(p -> sb.append(p).append("<br>").append("\n"));
                 sb.append("</td>");
                 return sb.toString();
--- a/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,219 +30,594 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import static java.util.stream.Collectors.*;
 
 /**
  * A build tool to extend the module-info.java in the source tree for
- * platform-specific exports, uses, and provides and write to the specified
- * output file. Injecting platform-specific requires is not supported.
+ * platform-specific exports, opens, uses, and provides and write to
+ * the specified output file.
+ *
+ * GenModuleInfoSource will be invoked for each module that has
+ * module-info.java.extra in the source directory.
  *
- * The extra exports, uses, provides can be specified in module-info.java.extra
- * files and GenModuleInfoSource will be invoked for each module that has
- * module-info.java.extra in the source directory.
+ * The extra exports, opens, uses, provides can be specified
+ * in module-info.java.extra.
+ * Injecting platform-specific requires is not supported.
+ *
+ * @see build.tools.module.ModuleInfoExtraTest for basic testing
  */
 public class GenModuleInfoSource {
     private final static String USAGE =
-        "Usage: GenModuleInfoSource [option] -o <output file> <module-info-java>\n" +
-        "Options are:\n" +
-        "  -exports  <package-name>\n" +
-        "  -exports  <package-name>[/<module-name>]\n" +
-        "  -uses     <service>\n" +
-        "  -provides <service>/<provider-impl-classname>\n";
+        "Usage: GenModuleInfoSource -o <output file> \n" +
+        "  --source-file <module-info-java>\n" +
+        "  --modules <module-name>[,<module-name>...]\n" +
+        "  <module-info.java.extra> ...\n";
 
+    static boolean verbose = false;
     public static void main(String... args) throws Exception {
         Path outfile = null;
         Path moduleInfoJava = null;
-        GenModuleInfoSource genModuleInfo = new GenModuleInfoSource();
-
+        Set<String> modules = Collections.emptySet();
+        List<Path> extras = new ArrayList<>();
         // validate input arguments
         for (int i = 0; i < args.length; i++){
             String option = args[i];
-            if (option.startsWith("-")) {
-                String arg = args[++i];
-                if (option.equals("-exports")) {
-                    int index = arg.indexOf('/');
-                        if (index > 0) {
-                            String pn = arg.substring(0, index);
-                            String mn = arg.substring(index + 1, arg.length());
-                            genModuleInfo.exportTo(pn, mn);
-                        } else {
-                            genModuleInfo.export(arg);
-                        }
-                } else if (option.equals("-uses")) {
-                    genModuleInfo.use(arg);
-                } else if (option.equals("-provides")) {
-                        int index = arg.indexOf('/');
-                        if (index <= 0) {
-                            throw new IllegalArgumentException("invalid -provide argument: " + arg);
-                        }
-                        String service = arg.substring(0, index);
-                        String impl = arg.substring(index + 1, arg.length());
-                        genModuleInfo.provide(service, impl);
-                } else if (option.equals("-o")) {
+            String arg = i+1 < args.length ? args[i+1] : null;
+            switch (option) {
+                case "-o":
                     outfile = Paths.get(arg);
-                } else {
-                    throw new IllegalArgumentException("invalid option: " + option);
-                }
-            } else if (moduleInfoJava != null) {
-                throw new IllegalArgumentException("more than one module-info.java");
-            } else {
-                moduleInfoJava = Paths.get(option);
-                if (Files.notExists(moduleInfoJava)) {
-                    throw new IllegalArgumentException(option + " not exist");
-                }
+                    i++;
+                    break;
+                case "--source-file":
+                    moduleInfoJava = Paths.get(arg);
+                    if (Files.notExists(moduleInfoJava)) {
+                        throw new IllegalArgumentException(moduleInfoJava + " not exist");
+                    }
+                    i++;
+                    break;
+                case "--modules":
+                    modules = Arrays.stream(arg.split(","))
+                                    .collect(toSet());
+                    i++;
+                    break;
+                case "-v":
+                    verbose = true;
+                    break;
+                default:
+                    Path file = Paths.get(option);
+                    if (Files.notExists(file)) {
+                        throw new IllegalArgumentException(file + " not exist");
+                    }
+                    extras.add(file);
             }
         }
 
-        if (moduleInfoJava == null || outfile == null) {
+        if (moduleInfoJava == null || outfile == null ||
+                modules.isEmpty() || extras.isEmpty()) {
             System.err.println(USAGE);
             System.exit(-1);
         }
 
-        // generate new module-info.java
-        genModuleInfo.generate(moduleInfoJava, outfile);
-    }
+        GenModuleInfoSource genModuleInfo =
+            new GenModuleInfoSource(moduleInfoJava, extras, modules);
 
-    private final Set<String> exports = new HashSet<>();
-    private final Map<String, Set<String>> exportsTo = new HashMap<>();
-    private final Set<String> uses = new HashSet<>();
-    private final Map<String, Set<String>> provides = new HashMap<>();
-    GenModuleInfoSource() {
+        // generate new module-info.java
+        genModuleInfo.generate(outfile);
     }
 
-    private void export(String p) {
-        Objects.requireNonNull(p);
-        if (exports.contains(p) || exportsTo.containsKey(p)) {
-            throw new RuntimeException("duplicated exports: " + p);
+    final Path sourceFile;
+    final List<Path> extraFiles;
+    final ModuleInfo extras;
+    final Set<String> modules;
+    final ModuleInfo moduleInfo;
+    GenModuleInfoSource(Path sourceFile, List<Path> extraFiles, Set<String> modules)
+        throws IOException
+    {
+        this.sourceFile = sourceFile;
+        this.extraFiles = extraFiles;
+        this.modules = modules;
+        this.moduleInfo = new ModuleInfo();
+        this.moduleInfo.parse(sourceFile);
+
+        // parse module-info.java.extra
+        this.extras = new ModuleInfo();
+        for (Path file : extraFiles) {
+            extras.parse(file);
         }
-        exports.add(p);
-    }
-    private void exportTo(String p, String mn) {
-        Objects.requireNonNull(p);
-        Objects.requireNonNull(mn);
-        if (exports.contains(p)) {
-            throw new RuntimeException("unqualified exports already exists: " + p);
-        }
-        exportsTo.computeIfAbsent(p, _k -> new HashSet<>()).add(mn);
+
+        // merge with module-info.java.extra
+        moduleInfo.augmentModuleInfo(extras, modules);
     }
 
-    private void use(String service) {
-        uses.add(service);
-    }
+    void generate(Path output) throws IOException {
+        List<String> lines = Files.readAllLines(sourceFile);
+        try (BufferedWriter bw = Files.newBufferedWriter(output);
+             PrintWriter writer = new PrintWriter(bw)) {
+            // write the copyright header and lines up to module declaration
+            for (String l : lines) {
+                writer.println(l);
+                if (l.trim().startsWith("module ")) {
+                    // print URI rather than file path to avoid escape
+                    writer.format("    // source file: %s%n", sourceFile.toUri());
+                    for (Path file: extraFiles) {
+                        writer.format("    //              %s%n", file.toUri());
+                    }
+                    break;
+                }
+            }
 
-    private void provide(String s, String impl) {
-        provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl);
+            // requires
+            for (String l : lines) {
+                if (l.trim().startsWith("requires"))
+                    writer.println(l);
+            }
+
+            // write exports, opens, uses, and provides
+            moduleInfo.print(writer);
+
+            // close
+            writer.println("}");
+        }
     }
 
-    private void generate(Path sourcefile, Path outfile) throws IOException {
-        Path parent = outfile.getParent();
-        if (parent != null)
-            Files.createDirectories(parent);
+
+    class ModuleInfo {
+        final Map<String, Statement> exports = new HashMap<>();
+        final Map<String, Statement> opens = new HashMap<>();
+        final Map<String, Statement> uses = new HashMap<>();
+        final Map<String, Statement> provides = new HashMap<>();
+
+        Statement getStatement(String directive, String name) {
+            switch (directive) {
+                case "exports":
+                    if (moduleInfo.exports.containsKey(name) &&
+                        moduleInfo.exports.get(name).isUnqualified()) {
+                        throw new IllegalArgumentException(sourceFile +
+                            " already has " + directive + " " + name);
+                    }
+                    return exports.computeIfAbsent(name,
+                        _n -> new Statement("exports", "to", name));
+
+                case "opens":
+                    if (moduleInfo.opens.containsKey(name) &&
+                        moduleInfo.opens.get(name).isUnqualified()) {
+                        throw new IllegalArgumentException(sourceFile +
+                            " already has " + directive + " " + name);
+                    }
+
+                    if (moduleInfo.opens.containsKey(name)) {
+                        throw new IllegalArgumentException(sourceFile +
+                            " already has " + directive + " " + name);
+                    }
+                    return opens.computeIfAbsent(name,
+                        _n -> new Statement("opens", "to", name));
+
+                case "uses":
+                    return uses.computeIfAbsent(name,
+                        _n -> new Statement("uses", "", name));
+
+                case "provides":
+                    return provides.computeIfAbsent(name,
+                        _n -> new Statement("provides", "with", name, true));
+
+                default:
+                    throw new IllegalArgumentException(directive);
+            }
+
+        }
+
+        /*
+         * Augment this ModuleInfo with module-info.java.extra
+         */
+        void augmentModuleInfo(ModuleInfo extraFiles, Set<String> modules) {
+            // API package exported in the original module-info.java
+            extraFiles.exports.entrySet()
+                .stream()
+                .filter(e -> exports.containsKey(e.getKey()) &&
+                                e.getValue().filter(modules))
+                .forEach(e -> mergeExportsOrOpens(exports.get(e.getKey()),
+                                                  e.getValue(),
+                                                  modules));
+
+            // add exports that are not defined in the original module-info.java
+            extraFiles.exports.entrySet()
+                .stream()
+                .filter(e -> !exports.containsKey(e.getKey()) &&
+                                e.getValue().filter(modules))
+                .forEach(e -> addTargets(getStatement("exports", e.getKey()),
+                                         e.getValue(),
+                                         modules));
+
+            // API package opened in the original module-info.java
+            extraFiles.opens.entrySet()
+                .stream()
+                .filter(e -> opens.containsKey(e.getKey()) &&
+                                e.getValue().filter(modules))
+                .forEach(e -> mergeExportsOrOpens(opens.get(e.getKey()),
+                                                  e.getValue(),
+                                                  modules));
+
+            // add opens that are not defined in the original module-info.java
+            extraFiles.opens.entrySet()
+                .stream()
+                .filter(e -> !opens.containsKey(e.getKey()) &&
+                                e.getValue().filter(modules))
+                .forEach(e -> addTargets(getStatement("opens", e.getKey()),
+                                         e.getValue(),
+                                         modules));
+
+            // provides
+            extraFiles.provides.keySet()
+                .stream()
+                .filter(service -> provides.containsKey(service))
+                .forEach(service -> mergeProvides(service,
+                                                  extraFiles.provides.get(service)));
+            extraFiles.provides.keySet()
+                .stream()
+                .filter(service -> !provides.containsKey(service))
+                .forEach(service -> provides.put(service,
+                                                 extraFiles.provides.get(service)));
+
+            // uses
+            extraFiles.uses.keySet()
+                .stream()
+                .filter(service -> !uses.containsKey(service))
+                .forEach(service -> uses.put(service, extraFiles.uses.get(service)));
+        }
+
+        // add qualified exports or opens to known modules only
+        private void addTargets(Statement statement,
+                                Statement extra,
+                                Set<String> modules)
+        {
+            extra.targets.stream()
+                 .filter(mn -> modules.contains(mn))
+                 .forEach(mn -> statement.addTarget(mn));
+        }
+
+        private void mergeExportsOrOpens(Statement statement,
+                                         Statement extra,
+                                         Set<String> modules)
+        {
+            String pn = statement.name;
+            if (statement.isUnqualified() && extra.isQualified()) {
+                throw new RuntimeException("can't add qualified exports to " +
+                    "unqualified exports " + pn);
+            }
+
+            Set<String> mods = extra.targets.stream()
+                .filter(mn -> statement.targets.contains(mn))
+                .collect(toSet());
+            if (mods.size() > 0) {
+                throw new RuntimeException("qualified exports " + pn + " to " +
+                    mods.toString() + " already declared in " + sourceFile);
+            }
+
+            // add qualified exports or opens to known modules only
+            addTargets(statement, extra, modules);
+        }
+
+        private void mergeProvides(String service, Statement extra) {
+            Statement statement = provides.get(service);
 
-        List<String> lines = Files.readAllLines(sourcefile);
-        try (BufferedWriter bw = Files.newBufferedWriter(outfile);
-             PrintWriter writer = new PrintWriter(bw)) {
-            int lineNumber = 0;
-            for (String l : lines) {
-                lineNumber++;
-                String[] s = l.trim().split("\\s+");
-                String keyword = s[0].trim();
-                int nextIndex = keyword.length();
-                String exp = null;
-                int n = l.length();
-                switch (keyword) {
-                    case "exports":
-                        boolean inExportsTo = false;
-                        // assume package name immediately after exports
-                        exp = s[1].trim();
-                        if (s.length >= 3) {
-                            nextIndex = l.indexOf(exp, nextIndex) + exp.length();
-                            if (s[2].trim().equals("to")) {
-                                inExportsTo = true;
-                                n = l.indexOf("to", nextIndex) + "to".length();
-                            } else {
+            Set<String> mods = extra.targets.stream()
+                .filter(mn -> statement.targets.contains(mn))
+                .collect(toSet());
+
+            if (mods.size() > 0) {
+                throw new RuntimeException("qualified exports " + service + " to " +
+                    mods.toString() + " already declared in " + sourceFile);
+            }
+
+            extra.targets.stream()
+                 .forEach(mn -> statement.addTarget(mn));
+        }
+
+
+        void print(PrintWriter writer) {
+            // print unqualified exports
+            exports.entrySet().stream()
+                .filter(e -> e.getValue().targets.isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+
+            // print qualified exports
+            exports.entrySet().stream()
+                .filter(e -> !e.getValue().targets.isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+
+            // print unqualified opens
+            opens.entrySet().stream()
+                .filter(e -> e.getValue().targets.isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+
+            // print qualified opens
+            opens.entrySet().stream()
+                .filter(e -> !e.getValue().targets.isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+
+            // uses and provides
+            writer.println();
+            uses.entrySet().stream()
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+            provides.entrySet().stream()
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+        }
+
+        private void parse(Path sourcefile) throws IOException {
+            List<String> lines = Files.readAllLines(sourcefile);
+            Statement statement = null;
+            boolean hasTargets = false;
+
+            for (int lineNumber = 1; lineNumber <= lines.size(); ) {
+                String l = lines.get(lineNumber-1).trim();
+                int index = 0;
+
+                if (l.isEmpty()) {
+                    lineNumber++;
+                    continue;
+                }
+
+                // comment block starts
+                if (l.startsWith("/*")) {
+                    while (l.indexOf("*/") == -1) { // end comment block
+                        l = lines.get(lineNumber++).trim();
+                    }
+                    index = l.indexOf("*/") + 2;
+                    if (index >= l.length()) {
+                        lineNumber++;
+                        continue;
+                    } else {
+                        // rest of the line
+                        l = l.substring(index, l.length()).trim();
+                        index = 0;
+                    }
+                }
+
+                // skip comment and annotations
+                if (l.startsWith("//") || l.startsWith("@")) {
+                    lineNumber++;
+                    continue;
+                }
+
+                int current = lineNumber;
+                int count = 0;
+                while (index < l.length()) {
+                    if (current == lineNumber && ++count > 20)
+                        throw new Error("Fail to parse line " + lineNumber + " " + sourcefile);
+
+                    int end = l.indexOf(';');
+                    if (end == -1)
+                        end = l.length();
+                    String content = l.substring(0, end).trim();
+                    if (content.isEmpty()) {
+                        index = end+1;
+                        if (index < l.length()) {
+                            // rest of the line
+                            l = l.substring(index, l.length()).trim();
+                            index = 0;
+                        }
+                        continue;
+                    }
+
+                    String[] s = content.split("\\s+");
+                    String keyword = s[0].trim();
+
+                    String name = s.length > 1 ? s[1].trim() : null;
+                    trace("%d: %s index=%d len=%d%n", lineNumber, l, index, l.length());
+                    switch (keyword) {
+                        case "module":
+                        case "requires":
+                        case "}":
+                            index = l.length();  // skip to the end
+                            continue;
+
+                        case "exports":
+                        case "opens":
+                        case "provides":
+                        case "uses":
+                            // assume name immediately after exports, opens, provides, uses
+                            statement = getStatement(keyword, name);
+                            hasTargets = false;
+
+                            int i = l.indexOf(name, keyword.length()+1) + name.length() + 1;
+                            l = i < l.length() ? l.substring(i, l.length()).trim() : "";
+                            index = 0;
+
+                            if (s.length >= 3) {
+                                if (!s[2].trim().equals(statement.qualifier)) {
+                                    throw new RuntimeException(sourcefile + ", line " +
+                                        lineNumber + ", is malformed: " + s[2]);
+                                }
+                            }
+
+                            break;
+
+                        case "to":
+                        case "with":
+                            if (statement == null) {
                                 throw new RuntimeException(sourcefile + ", line " +
-                                    lineNumber + ", is malformed: " + s[2]);
+                                    lineNumber + ", is malformed");
                             }
-                        }
+
+                            hasTargets = true;
+                            String qualifier = statement.qualifier;
+                            i = l.indexOf(qualifier, index) + qualifier.length() + 1;
+                            l = i < l.length() ? l.substring(i, l.length()).trim() : "";
+                            index = 0;
+                            break;
+                    }
 
-                        // inject the extra targets after "to"
-                        if (inExportsTo) {
-                            writer.println(injectExportTargets(exp, l, n));
+                    if (index >= l.length()) {
+                        // skip to next line
+                        continue;
+                    }
+
+                        // comment block starts
+                    if (l.startsWith("/*")) {
+                        while (l.indexOf("*/") == -1) { // end comment block
+                            l = lines.get(lineNumber++).trim();
+                        }
+                        index = l.indexOf("*/") + 2;
+                        if (index >= l.length()) {
+                            continue;
                         } else {
-                            writer.println(l);
+                            // rest of the line
+                            l = l.substring(index, l.length()).trim();
+                            index = 0;
                         }
-                        break;
-                    case "to":
-                        if (exp == null) {
-                            throw new RuntimeException(sourcefile + ", line " +
-                                lineNumber + ", is malformed");
-                        }
-                        n = l.indexOf("to", nextIndex) + "to".length();
-                        writer.println(injectExportTargets(exp, l, n));
-                        break;
-                    case "}":
-                        doAugments(writer);
-                        // fall through
-                    default:
-                        writer.println(l);
-                        // reset exports
-                        exp = null;
+                    }
+
+                    if (l.startsWith("//")) {
+                        index = l.length();
+                        continue;
+                    }
+
+                    if (statement == null) {
+                        throw new RuntimeException(sourcefile + ", line " +
+                            lineNumber + ": missing keyword?");
+                    }
+
+                    if (!hasTargets) {
+                        continue;
+                    }
+
+                    if (index >= l.length()) {
+                        throw new RuntimeException(sourcefile + ", line " +
+                            lineNumber + ": " + l);
+                    }
+
+                    // parse the target module of exports, opens, or provides
+                    Statement stmt = statement;
+
+                    int terminal = l.indexOf(';', index);
+                    // determine up to which position to parse
+                    int pos = terminal != -1 ? terminal : l.length();
+                    // parse up to comments
+                    int pos1 = l.indexOf("//", index);
+                    if (pos1 != -1 && pos1 < pos) {
+                        pos = pos1;
+                    }
+                    int pos2 = l.indexOf("/*", index);
+                    if (pos2 != -1 && pos2 < pos) {
+                        pos = pos2;
+                    }
+                    // target module(s) for qualitifed exports or opens
+                    // or provider implementation class(es)
+                    String rhs = l.substring(index, pos).trim();
+                    index += rhs.length();
+                    trace("rhs: index=%d [%s] [line: %s]%n", index, rhs, l);
+
+                    String[] targets = rhs.split(",");
+                    for (String t : targets) {
+                        String n = t.trim();
+                        if (n.length() > 0)
+                            stmt.addTarget(n);
+                    }
+
+                    // start next statement
+                    if (pos == terminal) {
+                        statement = null;
+                        hasTargets = false;
+                        index = terminal + 1;
+                    }
+                    l = index < l.length() ? l.substring(index, l.length()).trim() : "";
+                    index = 0;
                 }
+
+                lineNumber++;
             }
         }
     }
 
-    private String injectExportTargets(String pn, String exp, int pos) {
-        Set<String> targets = exportsTo.remove(pn);
-        if (targets != null) {
-            StringBuilder sb = new StringBuilder();
-            // inject the extra targets after the given pos
-            sb.append(exp.substring(0, pos))
-              .append("\n\t")
-              .append(targets.stream()
-                             .collect(Collectors.joining(",", "", ",")))
-              .append(" /* injected */");
-            if (pos < exp.length()) {
-                // print the remaining statement followed "to"
-                sb.append("\n\t")
-                  .append(exp.substring(pos+1, exp.length()));
+    static class Statement {
+        final String directive;
+        final String qualifier;
+        final String name;
+        final Set<String> targets = new LinkedHashSet<>();
+        final boolean ordered;
+
+        Statement(String directive, String qualifier, String name) {
+            this(directive, qualifier, name, false);
+        }
+
+        Statement(String directive, String qualifier, String name, boolean ordered) {
+            this.directive = directive;
+            this.qualifier = qualifier;
+            this.name = name;
+            this.ordered = ordered;
+        }
+
+        Statement addTarget(String mn) {
+            if (mn.isEmpty())
+                throw new IllegalArgumentException("empty module name");
+            targets.add(mn);
+            return this;
+        }
+
+        boolean isQualified() {
+            return targets.size() > 0;
+        }
+
+        boolean isUnqualified() {
+            return targets.isEmpty();
+        }
+
+        /**
+         * Returns true if this statement is unqualified or it has
+         * at least one target in the given names.
+         */
+        boolean filter(Set<String> names) {
+            if (isUnqualified()) {
+                return true;
+            } else {
+                return targets.stream()
+                    .filter(mn -> names.contains(mn))
+                    .findAny().isPresent();
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("    ");
+            sb.append(directive).append(" ").append(name);
+            if (targets.isEmpty()) {
+                sb.append(";");
+            } else if (targets.size() == 1) {
+                sb.append(" ").append(qualifier)
+                  .append(orderedTargets().collect(joining(",", " ", ";")));
+            } else {
+                sb.append(" ").append(qualifier)
+                  .append(orderedTargets()
+                      .map(target -> String.format("        %s", target))
+                      .collect(joining(",\n", "\n", ";")));
             }
             return sb.toString();
-        } else {
-            return exp;
+        }
+
+        public Stream<String> orderedTargets() {
+            return ordered ? targets.stream()
+                           : targets.stream().sorted();
         }
     }
 
-    private void doAugments(PrintWriter writer) {
-        if ((exports.size() + exportsTo.size() + uses.size() + provides.size()) == 0)
-            return;
-
-        writer.println("    // augmented from module-info.java.extra");
-        exports.stream()
-            .sorted()
-            .forEach(e -> writer.format("    exports %s;%n", e));
-        // remaining injected qualified exports
-        exportsTo.entrySet().stream()
-            .sorted(Map.Entry.comparingByKey())
-            .map(e -> String.format("    exports %s to%n%s;", e.getKey(),
-                                    e.getValue().stream().sorted()
-                                        .map(mn -> String.format("        %s", mn))
-                                        .collect(Collectors.joining(",\n"))))
-            .forEach(writer::println);
-        uses.stream().sorted()
-            .forEach(s -> writer.format("    uses %s;%n", s));
-        provides.entrySet().stream()
-            .sorted(Map.Entry.comparingByKey())
-            .flatMap(e -> e.getValue().stream().sorted()
-                           .map(impl -> String.format("    provides %s with %s;",
-                                                      e.getKey(), impl)))
-            .forEach(writer::println);
+    static void trace(String fmt, Object... params) {
+        if (verbose) {
+            System.out.format(fmt, params);
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/src/classes/build/tools/module/ModuleInfoExtraTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,243 @@
+/*
+ * 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.module;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import build.tools.module.GenModuleInfoSource.Statement;
+
+/**
+ * Sanity test for GenModuleInfoSource tool
+ */
+public class ModuleInfoExtraTest {
+    private static final Path DIR = Paths.get("test");
+    public static void main(String... args) throws Exception {
+        if (args.length != 0)
+            GenModuleInfoSource.verbose = true;
+
+        ModuleInfoExtraTest test = new ModuleInfoExtraTest("m", "m1", "m2", "m3");
+        test.run();
+    }
+
+    String[] moduleInfo = new String[] {
+        "exports p",
+        "to",
+        "   // comment",
+        "   /* comment */ m1",
+        ",",
+        "m2,m3",
+        "   ;",
+        "exports q to m1;",
+        "provides s with /* ",
+        "  comment */ impl     ;    // comment",
+        "provides s1",
+        "    with  ",
+        "    impl1, impl2;"
+    };
+
+    String[] moduleInfoExtra = new String[] {
+        "exports q",
+        "to",
+        "   m2 // comment",
+        "   /* comment */;",
+        "   ;",
+        "opens p.q ",
+        "   to /* comment */ m3",
+        "   , // m1",
+        "   /* comment */, m4;",
+        "provides s1 with impl3;"
+    };
+
+    String[] test1 = new String[] {
+        "exports p1 to m1;",
+        "exports p2"
+    };
+
+    String[] test2 = new String[] {
+        "exports to m1;"
+    };
+
+    String[] test3 = new String[]{
+        "exports p3 to m1;",
+        "    m2, m3;"
+    };
+
+    String[] test4 = new String[]{
+        "provides s with impl1;",   // typo ; should be ,
+        "   impl2, impl3;"
+    };
+
+    String[] test5 = new String[]{
+        "uses s3",
+        "provides s3 with impl1,",
+        "   impl2, impl3;"
+    };
+
+    final Builder builder;
+    ModuleInfoExtraTest(String name, String... modules) {
+        this.builder = new Builder(name).modules(modules);
+    }
+
+    void run() throws IOException {
+        testModuleInfo();
+        errorCases();
+    }
+
+
+    void testModuleInfo() throws IOException {
+        GenModuleInfoSource source = builder.sourceFile(moduleInfo).build();
+        Set<String> targetsP = new HashSet<>();
+        targetsP.add("m1");
+        targetsP.add("m2");
+        targetsP.add("m3");
+
+        Set<String> targetsQ = new HashSet<>();
+        targetsQ.add("m1");
+
+        Set<String> providerS = new HashSet<>();
+        providerS.add("impl");
+
+        Set<String> providerS1 = new HashSet<>();
+        providerS1.add("impl1");
+        providerS1.add("impl2");
+
+        Set<String> opensPQ = new HashSet<>();
+
+        check(source, targetsP, targetsQ, opensPQ, providerS, providerS1);
+
+        // augment with extra
+        Path file = DIR.resolve("extra");
+        Files.write(file, Arrays.asList(moduleInfoExtra));
+        source = builder.build(file);
+
+        targetsQ.add("m2");
+        providerS1.add("impl3");
+
+        opensPQ.add("m3");
+        check(source, targetsP, targetsQ, opensPQ, providerS, providerS1);
+    }
+
+    void check(GenModuleInfoSource source,
+               Set<String> targetsP,
+               Set<String> targetsQ,
+               Set<String> opensPQ,
+               Set<String> providerS,
+               Set<String> providerS1) {
+        source.moduleInfo.print(new PrintWriter(System.out, true));
+        Statement export = source.moduleInfo.exports.get("p");
+        if (!export.targets.equals(targetsP)) {
+            throw new Error("unexpected: " + export);
+        }
+
+        export = source.moduleInfo.exports.get("q");
+        if (!export.targets.equals(targetsQ)) {
+            throw new Error("unexpected: " + export);
+        }
+
+        Statement provides = source.moduleInfo.provides.get("s");
+        if (!provides.targets.equals(providerS)) {
+            throw new Error("unexpected: " + provides);
+        }
+
+        provides = source.moduleInfo.provides.get("s1");
+        if (!provides.targets.equals(providerS1)) {
+            throw new Error("unexpected: " + provides);
+        }
+    }
+
+
+
+    void errorCases() throws IOException {
+        fail(test1);
+        fail(test2);
+        fail(test3);
+        fail(test4);
+        fail(test5);
+    }
+
+    void fail(String... extras) throws IOException {
+        Path file = DIR.resolve("test1");
+        Files.write(file, Arrays.asList(extras));
+        try {
+            builder.build(file);
+        } catch (RuntimeException e) {
+            if (!e.getMessage().matches("test/test1, line .* is malformed.*") &&
+                !e.getMessage().matches("test/test1, line .* missing keyword.*")) {
+                throw e;
+            }
+        }
+    }
+
+    static class Builder {
+        final String moduleName;
+        final Path sourceFile;
+        final Set<String> modules = new HashSet<>();
+        public Builder(String name) {
+            this.moduleName = name;
+            this.sourceFile = DIR.resolve(name).resolve("module-info.java");
+        }
+
+        public Builder modules(String... names) {
+            Arrays.stream(names).forEach(modules::add);
+            return this;
+        }
+
+        public Builder sourceFile(String... lines) throws IOException {
+            Files.createDirectories(sourceFile.getParent());
+            try (BufferedWriter bw = Files.newBufferedWriter(sourceFile);
+                 PrintWriter writer = new PrintWriter(bw)) {
+                writer.format("module %s {%n", moduleName);
+                for (String l : lines) {
+                    writer.println(l);
+                }
+                writer.println("}");
+            }
+            return this;
+        }
+
+        public GenModuleInfoSource build() throws IOException {
+            return build(Collections.emptyList());
+        }
+
+        public GenModuleInfoSource build(Path extraFile) throws IOException {
+            return build(Collections.singletonList(extraFile));
+        }
+
+        public GenModuleInfoSource build(List<Path> extraFiles) throws IOException {
+            return new GenModuleInfoSource(sourceFile, extraFiles, modules);
+        }
+    }
+
+}
--- a/jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -47,6 +47,7 @@
 import java.util.spi.CurrencyNameProvider;
 import java.util.spi.LocaleNameProvider;
 import java.util.spi.TimeZoneNameProvider;
+import sun.text.spi.JavaTimeDateTimePatternProvider;
 import sun.util.spi.CalendarProvider;
 
 /**
@@ -147,6 +148,165 @@
         return Locale.forLanguageTag(langTag);
     }
 
+    public static JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
+        return new JavaTimeDateTimePatternProvider() {
+            @Override
+            public Locale[] getAvailableLocales() {
+                return getSupportedCalendarLocales();
+            }
+
+            @Override
+            public boolean isSupportedLocale(Locale locale) {
+                return isSupportedCalendarLocale(locale);
+            }
+
+            @Override
+            public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
+                return toJavaTimeDateTimePattern(calType, getDateTimePattern(dateStyle, timeStyle, locale));
+
+            }
+
+            private String getDateTimePattern(int dateStyle, int timeStyle, Locale locale) {
+                AtomicReferenceArray<String> dateFormatPatterns;
+                SoftReference<AtomicReferenceArray<String>> ref = dateFormatPatternsMap.get(locale);
+
+                if (ref == null || (dateFormatPatterns = ref.get()) == null) {
+                    dateFormatPatterns = new AtomicReferenceArray<>(5 * 5);
+                    ref = new SoftReference<>(dateFormatPatterns);
+                    dateFormatPatternsMap.put(locale, ref);
+                }
+                int index = (dateStyle + 1) * 5 + timeStyle + 1;
+                String pattern = dateFormatPatterns.get(index);
+                if (pattern == null) {
+                    String langTag = locale.toLanguageTag();
+                    pattern = translateDateFormatLetters(getCalendarID(langTag),
+                            getDateTimePatternNative(dateStyle, timeStyle, langTag));
+                    if (!dateFormatPatterns.compareAndSet(index, null, pattern)) {
+                        pattern = dateFormatPatterns.get(index);
+                    }
+                }
+                return pattern;
+            }
+
+            /**
+             * This method will convert JRE Date/time Pattern String to JSR310
+             * type Date/Time Pattern
+             */
+            private String toJavaTimeDateTimePattern(String calendarType, String jrePattern) {
+                int length = jrePattern.length();
+                StringBuilder sb = new StringBuilder(length);
+                boolean inQuote = false;
+                int count = 0;
+                char lastLetter = 0;
+                for (int i = 0; i < length; i++) {
+                    char c = jrePattern.charAt(i);
+                    if (c == '\'') {
+                        // '' is treated as a single quote regardless of being
+                        // in a quoted section.
+                        if ((i + 1) < length) {
+                            char nextc = jrePattern.charAt(i + 1);
+                            if (nextc == '\'') {
+                                i++;
+                                if (count != 0) {
+                                    convert(calendarType, lastLetter, count, sb);
+                                    lastLetter = 0;
+                                    count = 0;
+                                }
+                                sb.append("''");
+                                continue;
+                            }
+                        }
+                        if (!inQuote) {
+                            if (count != 0) {
+                                convert(calendarType, lastLetter, count, sb);
+                                lastLetter = 0;
+                                count = 0;
+                            }
+                            inQuote = true;
+                        } else {
+                            inQuote = false;
+                        }
+                        sb.append(c);
+                        continue;
+                    }
+                    if (inQuote) {
+                        sb.append(c);
+                        continue;
+                    }
+                    if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
+                        if (count != 0) {
+                            convert(calendarType, lastLetter, count, sb);
+                            lastLetter = 0;
+                            count = 0;
+                        }
+                        sb.append(c);
+                        continue;
+                    }
+                    if (lastLetter == 0 || lastLetter == c) {
+                        lastLetter = c;
+                        count++;
+                        continue;
+                    }
+                    convert(calendarType, lastLetter, count, sb);
+                    lastLetter = c;
+                    count = 1;
+                }
+                if (inQuote) {
+                    // should not come here.
+                    // returning null so that FALLBACK provider will kick in.
+                    return null;
+                }
+                if (count != 0) {
+                    convert(calendarType, lastLetter, count, sb);
+                }
+                return sb.toString();
+            }
+
+            private void convert(String calendarType, char letter, int count, StringBuilder sb) {
+                switch (letter) {
+                    case 'G':
+                        if (calendarType.equals("japanese")) {
+                            if (count >= 4) {
+                                count = 1;
+                            } else {
+                                count = 5;
+                            }
+                        } else if (!calendarType.equals("iso8601")) {
+                            // Gregorian calendar is iso8601 for java.time
+                            // Adjust the number of 'G's
+                            if (count >= 4) {
+                                // JRE full -> JavaTime full
+                                count = 4;
+                            } else {
+                                // JRE short -> JavaTime short
+                                count = 1;
+                            }
+                        }
+                        break;
+                    case 'y':
+                        if (calendarType.equals("japanese") && count >= 4) {
+                            // JRE specific "gan-nen" support
+                            count = 1;
+                        }
+                        break;
+                    default:
+                        // JSR 310 and CLDR define 5-letter patterns for narrow text.
+                        if (count > 4) {
+                            count = 4;
+                        }
+                        break;
+                }
+                appendN(letter, count, sb);
+            }
+
+            private void appendN(char c, int n, StringBuilder sb) {
+                for (int i = 0; i < n; i++) {
+                    sb.append(c);
+                }
+            }
+        };
+    }
+
     public static DateFormatProvider getDateFormatProvider() {
         return new DateFormatProvider() {
 
@@ -163,20 +323,20 @@
             @Override
             public DateFormat getDateInstance(int style, Locale locale) {
                 return new SimpleDateFormat(getDateTimePattern(style, -1, locale),
-                                            getCalendarLocale(locale));
+                        getCalendarLocale(locale));
             }
 
             @Override
             public DateFormat getTimeInstance(int style, Locale locale) {
                 return new SimpleDateFormat(getDateTimePattern(-1, style, locale),
-                                            getCalendarLocale(locale));
+                        getCalendarLocale(locale));
             }
 
             @Override
             public DateFormat getDateTimeInstance(int dateStyle,
                     int timeStyle, Locale locale) {
                 return new SimpleDateFormat(getDateTimePattern(dateStyle, timeStyle, locale),
-                                            getCalendarLocale(locale));
+                        getCalendarLocale(locale));
             }
 
             private String getDateTimePattern(int dateStyle, int timeStyle, Locale locale) {
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -15,12 +15,12 @@
 pack.class.attribute.CompilationID = RUH
 
 # Module attributes, supported by the tool and not JSR-200
-pack.class.attribute.Module = NH[RUHFH]NH[RUHNH[RUH]]NH[RCH]NH[RCHRCH]
-pack.class.attribute.ConcealedPackages = NH[RUH]
-pack.class.attribute.Version = RUH
-pack.class.attribute.MainClass = RCH
-pack.class.attribute.TargetPlatform = RUHRUHRUH
-pack.class.attribute.Hashes = RUHNH[RUHRUH]
+pack.class.attribute.Module = RUHFHNH[RUHFH]NH[RUHFHNH[RUH]]NH[RUHFHNH[RUH]]NH[RCH]NH[RCHNH[RCH]]
+pack.class.attribute.ModulePackages = NH[RUH]
+pack.class.attribute.ModuleVersion = RUH
+pack.class.attribute.ModuleMainClass = RCH
+pack.class.attribute.ModuleTarget = RUHRUHRUH
+pack.class.attribute.ModuleHashes = RUHNH[RUHNH[B]]
 
 
 # Note:  Zero-length ("marker") attributes do not need to be specified here.
--- a/jdk/src/java.base/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -39,6 +39,7 @@
 import java.net.Proxy;
 import java.net.ProtocolException;
 import java.io.*;
+import java.net.Authenticator;
 import javax.net.ssl.*;
 import java.security.Permission;
 import java.util.Map;
@@ -489,4 +490,9 @@
     public void setChunkedStreamingMode (int chunklen) {
         delegate.setChunkedStreamingMode(chunklen);
     }
+
+    @Override
+    public void setAuthenticator(Authenticator auth) {
+        delegate.setAuthenticator(auth);
+    }
 }
--- a/jdk/src/java.base/share/classes/java/io/FilePermission.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/io/FilePermission.java	Wed Jul 05 22:32:06 2017 +0200
@@ -216,19 +216,28 @@
             GetPropertyAction.privilegedGetProperty("user.dir"));
 
     /**
-     * A private constructor like a clone, only npath2 is not touched.
+     * A private constructor that clones some and updates some,
+     * always with a different name.
      * @param input
      */
-    private FilePermission(String name, FilePermission input) {
+    private FilePermission(String name,
+                           FilePermission input,
+                           Path npath,
+                           Path npath2,
+                           int mask,
+                           String actions) {
         super(name);
-        this.npath = input.npath;
-        this.actions = input.actions;
+        // Customizables
+        this.npath = npath;
+        this.npath2 = npath2;
+        this.actions = actions;
+        this.mask = mask;
+        // Cloneds
         this.allFiles = input.allFiles;
         this.invalid = input.invalid;
         this.recursive = input.recursive;
         this.directory = input.directory;
         this.cpath = input.cpath;
-        this.mask = input.mask;
     }
 
     /**
@@ -261,10 +270,12 @@
                             // different than the original so that when one is
                             // added to a FilePermissionCollection it will not
                             // be merged with the original one.
-                            FilePermission np = new FilePermission(
-                                    input.getName()+"#plus", input);
-                            np.npath2 = npath2;
-                            return np;
+                            return new FilePermission(input.getName() + "#plus",
+                                    input,
+                                    input.npath,
+                                    npath2,
+                                    input.mask,
+                                    input.actions);
                         }
                     }
                     return input;
@@ -274,10 +285,12 @@
                         Path npath2 = altPath(input.npath);
                         if (npath2 != null) {
                             // New name, see above.
-                            FilePermission np = new FilePermission(
-                                    input.getName()+"#using", input);
-                            np.npath = npath2;
-                            return np;
+                            return new FilePermission(input.getName() + "#using",
+                                    input,
+                                    npath2,
+                                    null,
+                                    input.mask,
+                                    input.actions);
                         }
                     }
                     return null;
@@ -981,6 +994,20 @@
         s.defaultReadObject();
         init(getMask(actions));
     }
+
+    /**
+     * Create a cloned FilePermission with a different actions.
+     * @param effective the new actions
+     * @return a new object
+     */
+    FilePermission withNewActions(int effective) {
+        return new FilePermission(this.getName(),
+                this,
+                this.npath,
+                this.npath2,
+                effective,
+                null);
+    }
 }
 
 /**
@@ -1048,8 +1075,7 @@
         FilePermission fp = (FilePermission)permission;
 
         // Add permission to map if it is absent, or replace with new
-        // permission if applicable. NOTE: cannot use lambda for
-        // remappingFunction parameter until JDK-8076596 is fixed.
+        // permission if applicable.
         perms.merge(fp.getName(), fp,
             new java.util.function.BiFunction<>() {
                 @Override
@@ -1063,7 +1089,8 @@
                             return newVal;
                         }
                         if (effective != oldMask) {
-                            return new FilePermission(fp.getName(), effective);
+                            return ((FilePermission)newVal)
+                                    .withNewActions(effective);
                         }
                     }
                     return existingVal;
--- a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1553,13 +1553,20 @@
      */
     @Override
     public IntStream chars() {
-        byte[] val = this.value; int count = this.count; byte coder = this.coder;
-        checkOffset(count, val.length >> coder);
         // Reuse String-based spliterator. This requires a supplier to
         // capture the value and count when the terminal operation is executed
         return StreamSupport.intStream(
-                () -> coder == LATIN1 ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
-                                      : new StringUTF16.CharsSpliterator(val, 0, count, 0),
+                () -> {
+                    // The combined set of field reads are not atomic and thread
+                    // safe but bounds checks will ensure no unsafe reads from
+                    // the byte array
+                    byte[] val = this.value;
+                    int count = this.count;
+                    byte coder = this.coder;
+                    return coder == LATIN1
+                           ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
+                           : new StringUTF16.CharsSpliterator(val, 0, count, 0);
+                },
                 Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED,
                 false);
     }
@@ -1570,13 +1577,20 @@
      */
     @Override
     public IntStream codePoints() {
-        byte[] val = this.value; int count = this.count; byte coder = this.coder;
-        checkOffset(count, val.length >> coder);
         // Reuse String-based spliterator. This requires a supplier to
         // capture the value and count when the terminal operation is executed
         return StreamSupport.intStream(
-                () -> coder == LATIN1 ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
-                                      : new StringUTF16.CodePointsSpliterator(val, 0, count, 0),
+                () -> {
+                    // The combined set of field reads are not atomic and thread
+                    // safe but bounds checks will ensure no unsafe reads from
+                    // the byte array
+                    byte[] val = this.value;
+                    int count = this.count;
+                    byte coder = this.coder;
+                    return coder == LATIN1
+                           ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
+                           : new StringUTF16.CodePointsSpliterator(val, 0, count, 0);
+                },
                 Spliterator.ORDERED,
                 false);
     }
--- a/jdk/src/java.base/share/classes/java/lang/Class.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,46 +26,55 @@
 package java.lang;
 
 import java.lang.annotation.Annotation;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReader;
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Array;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.GenericDeclaration;
-import java.lang.reflect.Member;
-import java.lang.reflect.Field;
-import java.lang.reflect.Executable;
-import java.lang.reflect.Method;
-import java.lang.reflect.Module;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.AnnotatedType;
-import java.lang.reflect.Proxy;
 import java.lang.ref.SoftReference;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectStreamField;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Objects;
 import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
 import jdk.internal.HotSpotIntrinsicCandidate;
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
+import jdk.internal.loader.ResourceHelper;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.misc.VM;
+import jdk.internal.module.ModuleHashes;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.ConstantPool;
 import jdk.internal.reflect.Reflection;
@@ -442,21 +451,10 @@
 
         PrivilegedAction<ClassLoader> pa = module::getClassLoader;
         ClassLoader cl = AccessController.doPrivileged(pa);
-        if (module.isNamed() && cl != null) {
-            return cl.loadLocalClass(module, name);
-        }
-
-        final Class<?> c;
         if (cl != null) {
-            c = cl.loadLocalClass(name);
+            return cl.loadClass(module, name);
         } else {
-            c = BootLoader.loadClassOrNull(name);
-        }
-
-        if (c != null && c.getModule() == module) {
-            return c;
-        } else {
-            return null;
+            return BootLoader.loadClass(module, name);
         }
     }
 
@@ -979,7 +977,7 @@
     }
 
     // cached package name
-    private String packageName;
+    private transient String packageName;
 
     /**
      * Returns the interfaces directly implemented by the class or interface
@@ -1976,6 +1974,22 @@
         return method;
     }
 
+    /**
+     * Returns a {@code Method} object that reflects the specified public
+     * member method of the class or interface represented by this
+     * {@code Class} object.
+     *
+     * @param name the name of the method
+     * @param parameterTypes the list of parameters
+     * @return the {@code Method} object that matches the specified
+     *         {@code name} and {@code parameterTypes}; {@code null}
+     *         if the method is not found or the name is
+     *         "&lt;init&gt;"or "&lt;clinit&gt;".
+     */
+    Method getMethodOrNull(String name, Class<?>... parameterTypes) {
+        return getMethod0(name, parameterTypes, true);
+    }
+
 
     /**
      * Returns a {@code Constructor} object that reflects the specified
@@ -2367,12 +2381,17 @@
     }
 
     /**
-     * Finds a resource with a given name. If this class is in a named {@link
-     * Module Module}, and the caller of this method is in the same module,
-     * then this method will attempt to find the resource in that module.
-     * Otherwise, the rules for searching resources
-     * associated with a given class are implemented by the defining
-     * {@linkplain ClassLoader class loader} of the class.  This method
+     * Finds a resource with a given name.
+     *
+     * <p> If this class is in a named {@link Module Module} then this method
+     * will attempt to find the resource in the module by means of the absolute
+     * resource name, subject to the rules for encapsulation specified in the
+     * {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
+     * method.
+     *
+     * <p> Otherwise, if this class is not in a named module then the rules for
+     * searching resources associated with a given class are implemented by the
+     * defining {@linkplain ClassLoader class loader} of the class.  This method
      * delegates to this object's class loader.  If this object was loaded by
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResourceAsStream}.
@@ -2400,8 +2419,11 @@
      * </ul>
      *
      * @param  name name of the desired resource
-     * @return  A {@link java.io.InputStream} object or {@code null} if
-     *          no resource with this name is found
+     * @return  A {@link java.io.InputStream} object; {@code null} if no
+     *          resource with this name is found, the resource is in a package
+     *          that is not {@link Module#isOpen(String, Module) open} to at
+     *          least the caller module, or access to the resource is denied
+     *          by the security manager.
      * @throws  NullPointerException If {@code name} is {@code null}
      * @since  1.1
      */
@@ -2409,35 +2431,41 @@
     public InputStream getResourceAsStream(String name) {
         name = resolveName(name);
 
-        // if this Class and the caller are in the same named module
-        // then attempt to get an input stream to the resource in the
-        // module
         Module module = getModule();
         if (module.isNamed()) {
-            Class<?> caller = Reflection.getCallerClass();
-            if (caller != null && caller.getModule() == module) {
-                ClassLoader cl = getClassLoader0();
-                String mn = module.getName();
-                try {
-
-                    // special-case built-in class loaders to avoid the
-                    // need for a URL connection
-                    if (cl == null) {
-                        return BootLoader.findResourceAsStream(mn, name);
-                    } else if (cl instanceof BuiltinClassLoader) {
-                        return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
-                    } else {
-                        URL url = cl.findResource(mn, name);
-                        return (url != null) ? url.openStream() : null;
+            if (!ResourceHelper.isSimpleResource(name)) {
+                Module caller = Reflection.getCallerClass().getModule();
+                if (caller != module) {
+                    Set<String> packages = module.getDescriptor().packages();
+                    String pn = ResourceHelper.getPackageName(name);
+                    if (packages.contains(pn) && !module.isOpen(pn, caller)) {
+                        // resource is in package not open to caller
+                        return null;
                     }
-
-                } catch (IOException | SecurityException e) {
-                    return null;
                 }
             }
+
+            String mn = module.getName();
+            ClassLoader cl = getClassLoader0();
+            try {
+
+                // special-case built-in class loaders to avoid the
+                // need for a URL connection
+                if (cl == null) {
+                    return BootLoader.findResourceAsStream(mn, name);
+                } else if (cl instanceof BuiltinClassLoader) {
+                    return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
+                } else {
+                    URL url = cl.findResource(mn, name);
+                    return (url != null) ? url.openStream() : null;
+                }
+
+            } catch (IOException | SecurityException e) {
+                return null;
+            }
         }
 
-        // this Class and caller not in the same named module
+        // unnamed module
         ClassLoader cl = getClassLoader0();
         if (cl == null) {
             return ClassLoader.getSystemResourceAsStream(name);
@@ -2447,12 +2475,17 @@
     }
 
     /**
-     * Finds a resource with a given name. If this class is in a named {@link
-     * Module Module}, and the caller of this method is in the same module,
-     * then this method will attempt to find the resource in that module.
-     * Otherwise, the rules for searching resources
-     * associated with a given class are implemented by the defining
-     * {@linkplain ClassLoader class loader} of the class.  This method
+     * Finds a resource with a given name.
+     *
+     * <p> If this class is in a named {@link Module Module} then this method
+     * will attempt to find the resource in the module by means of the absolute
+     * resource name, subject to the rules for encapsulation specified in the
+     * {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
+     * method.
+     *
+     * <p> Otherwise, if this class is not in a named module then the rules for
+     * searching resources associated with a given class are implemented by the
+     * defining {@linkplain ClassLoader class loader} of the class.  This method
      * delegates to this object's class loader. If this object was loaded by
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResource}.
@@ -2479,35 +2512,46 @@
      * </ul>
      *
      * @param  name name of the desired resource
-     * @return A {@link java.net.URL} object; {@code null} if no
-     *         resource with this name is found or the resource cannot
-     *         be located by a URL.
+     * @return A {@link java.net.URL} object; {@code null} if no resource with
+     *         this name is found, the resource cannot be located by a URL, the
+     *         resource is in a package that is not
+     *         {@link Module#isOpen(String, Module) open} to at least the caller
+     *         module, or access to the resource is denied by the security
+     *         manager.
+     * @throws NullPointerException If {@code name} is {@code null}
      * @since  1.1
      */
     @CallerSensitive
     public URL getResource(String name) {
         name = resolveName(name);
 
-        // if this Class and the caller are in the same named module
-        // then attempt to get URL to the resource in the module
         Module module = getModule();
         if (module.isNamed()) {
-            Class<?> caller = Reflection.getCallerClass();
-            if (caller != null && caller.getModule() == module) {
-                String mn = getModule().getName();
-                ClassLoader cl = getClassLoader0();
-                try {
-                    if (cl == null) {
-                        return BootLoader.findResource(mn, name);
-                    } else {
-                        return cl.findResource(mn, name);
+            if (!ResourceHelper.isSimpleResource(name)) {
+                Module caller = Reflection.getCallerClass().getModule();
+                if (caller != module) {
+                    Set<String> packages = module.getDescriptor().packages();
+                    String pn = ResourceHelper.getPackageName(name);
+                    if (packages.contains(pn) && !module.isOpen(pn, caller)) {
+                        // resource is in package not open to caller
+                        return null;
                     }
-                } catch (IOException ioe) {
-                    return null;
                 }
             }
+            String mn = getModule().getName();
+            ClassLoader cl = getClassLoader0();
+            try {
+                if (cl == null) {
+                    return BootLoader.findResource(mn, name);
+                } else {
+                    return cl.findResource(mn, name);
+                }
+            } catch (IOException ioe) {
+                return null;
+            }
         }
 
+        // unnamed module
         ClassLoader cl = getClassLoader0();
         if (cl == null) {
             return ClassLoader.getSystemResource(name);
@@ -2632,9 +2676,6 @@
      * if name is absolute
      */
     private String resolveName(String name) {
-        if (name == null) {
-            return name;
-        }
         if (!name.startsWith("/")) {
             Class<?> c = this;
             while (c.isArray()) {
--- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -42,15 +42,14 @@
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Set;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.Stack;
-import java.util.NoSuchElementException;
 import java.util.Vector;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
@@ -59,7 +58,6 @@
 import java.util.stream.StreamSupport;
 
 import jdk.internal.perf.PerfCounter;
-import jdk.internal.module.ServicesCatalog;
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.ClassLoaders;
 import jdk.internal.misc.SharedSecrets;
@@ -411,7 +409,6 @@
         this(checkCreateClassLoader(), null, parent);
     }
 
-
     /**
      * Creates a new class loader using the <tt>ClassLoader</tt> returned by
      * the method {@link #getSystemClassLoader()
@@ -431,7 +428,6 @@
         this(checkCreateClassLoader(), null, getSystemClassLoader());
     }
 
-
     /**
      * Returns the name of this class loader or {@code null} if
      * this class loader is not named.
@@ -581,7 +577,7 @@
      * @return The resulting {@code Class} object in a module defined by
      *         this class loader, or {@code null} if the class could not be found.
      */
-    final Class<?> loadLocalClass(Module module, String name) {
+    final Class<?> loadClass(Module module, String name) {
         synchronized (getClassLoadingLock(name)) {
             // First, check if the class has already been loaded
             Class<?> c = findLoadedClass(name);
@@ -597,34 +593,6 @@
     }
 
     /**
-     * Loads the class with the specified <a href="#name">binary name</a>
-     * defined by this class loader.  This method returns {@code null}
-     * if the class could not be found.
-     *
-     * @apiNote This method does not delegate to the parent class loader.
-     *
-     * @param  name
-     *         The <a href="#name">binary name</a> of the class
-     *
-     * @return The resulting {@code Class} object in a module defined by
-     *         this class loader, or {@code null} if the class could not be found.
-     */
-    final Class<?> loadLocalClass(String name) {
-        synchronized (getClassLoadingLock(name)) {
-            // First, check if the class has already been loaded
-            Class<?> c = findLoadedClass(name);
-            if (c == null) {
-                try {
-                    return findClass(name);
-                } catch (ClassNotFoundException e) {
-                    // ignore
-                }
-            }
-            return c;
-        }
-    }
-
-    /**
      * Returns the lock object for class loading operations.
      * For backward compatibility, the default implementation of this method
      * behaves as follows. If this ClassLoader object is registered as
@@ -724,12 +692,17 @@
      * should override this method.
      *
      * @apiNote This method returns {@code null} rather than throwing
-     *          {@code ClassNotFoundException} if the class could not be found
+     *          {@code ClassNotFoundException} if the class could not be found.
      *
-     * @implSpec The default implementation returns {@code null}.
+     * @implSpec The default implementation attempts to find the class by
+     * invoking {@link #findClass(String)} when the {@code moduleName} is
+     * {@code null}. It otherwise returns {@code null}.
      *
      * @param  moduleName
-     *         The module name
+     *         The module name; or {@code null} to find the class in the
+     *         {@linkplain #getUnnamedModule() unnamed module} for this
+     *         class loader
+
      * @param  name
      *         The <a href="#name">binary name</a> of the class
      *
@@ -739,6 +712,11 @@
      * @since 9
      */
     protected Class<?> findClass(String moduleName, String name) {
+        if (moduleName == null) {
+            try {
+                return findClass(name);
+            } catch (ClassNotFoundException ignore) { }
+        }
         return null;
     }
 
@@ -1286,10 +1264,20 @@
      * Class loader implementations that support the loading from modules
      * should override this method.
      *
-     * @implSpec The default implementation returns {@code null}.
+     * @apiNote This method is the basis for the {@code Class} {@link
+     * Class#getResource getResource} and {@link Class#getResourceAsStream
+     * getResourceAsStream} methods. It is not subject to the rules for
+     * encapsulation specified by {@code Module} {@link
+     * Module#getResourceAsStream getResourceAsStream}.
+     *
+     * @implSpec The default implementation attempts to find the resource by
+     * invoking {@link #findResource(String)} when the {@code moduleName} is
+     * {@code null}. It otherwise returns {@code null}.
      *
      * @param  moduleName
-     *         The module name
+     *         The module name; or {@code null} to find a resource in the
+     *         {@linkplain #getUnnamedModule() unnamed module} for this
+     *         class loader
      * @param  name
      *         The resource name
      *
@@ -1306,7 +1294,11 @@
      * @since 9
      */
     protected URL findResource(String moduleName, String name) throws IOException {
-        return null;
+        if (moduleName == null) {
+            return findResource(name);
+        } else {
+            return null;
+        }
     }
 
     /**
@@ -1314,9 +1306,6 @@
      * (images, audio, text, etc) that can be accessed by class code in a way
      * that is independent of the location of the code.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resource in named modules.
-     *
      * <p> The name of a resource is a '<tt>/</tt>'-separated path name that
      * identifies the resource.
      *
@@ -1325,16 +1314,31 @@
      * built-in to the virtual machine is searched.  That failing, this method
      * will invoke {@link #findResource(String)} to find the resource.  </p>
      *
-     * @apiNote When overriding this method it is recommended that an
-     * implementation ensures that any delegation is consistent with the {@link
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally (even if the caller of this method is in the
+     * same module as the resource). </p>
+     *
+     * @apiNote Where several modules are defined to the same class loader,
+     * and where more than one module contains a resource with the given name,
+     * then the ordering that modules are searched is not specified and may be
+     * very unpredictable.
+     * When overriding this method it is recommended that an implementation
+     * ensures that any delegation is consistent with the {@link
      * #getResources(java.lang.String) getResources(String)} method.
      *
      * @param  name
      *         The resource name
      *
-     * @return  A <tt>URL</tt> object for reading the resource, or
-     *          <tt>null</tt> if the resource could not be found or the invoker
-     *          doesn't have adequate  privileges to get the resource.
+     * @return  {@code URL} object for reading the resource; {@code null} if
+     *          the resource could not be found, a {@code URL} could not be
+     *          constructed to locate the resource, the resource is in a package
+     *          that is not opened unconditionally, or access to the resource is
+     *          denied by the security manager.
+     *
      * @throws  NullPointerException If {@code name} is {@code null}
      *
      * @since  1.1
@@ -1358,16 +1362,24 @@
      * (images, audio, text, etc) that can be accessed by class code in a way
      * that is independent of the location of the code.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
-     *
-     * <p>The name of a resource is a <tt>/</tt>-separated path name that
+     * <p> The name of a resource is a <tt>/</tt>-separated path name that
      * identifies the resource.
      *
-     * <p> The search order is described in the documentation for {@link
-     * #getResource(String)}.  </p>
+     * <p> The delegation order for searching is described in the documentation
+     * for {@link #getResource(String)}.  </p>
      *
-     * @apiNote When overriding this method it is recommended that an
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally (even if the caller of this method is in the
+     * same module as the resource).</p>
+     *
+     * @apiNote Where several modules are defined to the same class loader,
+     * and where more than one module contains a resource with the given name,
+     * then the ordering is not specified and may be very unpredictable.
+     * When overriding this method it is recommended that an
      * implementation ensures that any delegation is consistent with the {@link
      * #getResource(java.lang.String) getResource(String)} method. This should
      * ensure that the first element returned by the Enumeration's
@@ -1378,9 +1390,11 @@
      *         The resource name
      *
      * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
-     *          the resource.  If no resources could  be found, the enumeration
-     *          will be empty.  Resources that the class loader doesn't have
-     *          access to will not be in the enumeration.
+     *          the resource. If no resources could  be found, the enumeration
+     *          will be empty. Resources for which a {@code URL} cannot be
+     *          constructed, are in package that is not opened unconditionally,
+     *          or access to the resource is denied by the security manager,
+     *          are not returned in the enumeration.
      *
      * @throws  IOException
      *          If I/O errors occur
@@ -1410,9 +1424,6 @@
      * can be accessed by class code in a way that is independent of the
      * location of the code.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
-     *
      * <p> The name of a resource is a {@code /}-separated path name that
      * identifies the resource.
      *
@@ -1424,6 +1435,14 @@
      * exception is wrapped in an {@link UncheckedIOException} that is then
      * thrown.
      *
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally (even if the caller of this method is in the
+     * same module as the resource). </p>
+     *
      * @apiNote When overriding this method it is recommended that an
      * implementation ensures that any delegation is consistent with the {@link
      * #getResource(java.lang.String) getResource(String)} method. This should
@@ -1434,9 +1453,10 @@
      *         The resource name
      *
      * @return  A stream of resource {@link java.net.URL URL} objects. If no
-     *          resources could  be found, the stream will be empty.  Resources
-     *          that the class loader doesn't have access to will not be in the
-     *          stream.
+     *          resources could  be found, the stream will be empty. Resources
+     *          for which a {@code URL} cannot be constructed, are in a package
+     *          that is not opened unconditionally, or access to the resource
+     *          is denied by the security manager, will not be in the stream.
      *
      * @throws  NullPointerException If {@code name} is {@code null}
      *
@@ -1462,14 +1482,21 @@
      * Finds the resource with the given name. Class loader implementations
      * should override this method to specify where to find resources.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules defined to this class loader.
+     * <p> For resources in named modules then the method must implement the
+     * rules for encapsulation specified in the {@code Module} {@link
+     * Module#getResourceAsStream getResourceAsStream} method. Additionally,
+     * it must not find non-"{@code .class}" resources in packages of named
+     * modules unless the package is {@link Module#isOpen(String) opened}
+     * unconditionally. </p>
      *
      * @param  name
      *         The resource name
      *
-     * @return  A <tt>URL</tt> object for reading the resource, or
-     *          <tt>null</tt> if the resource could not be found
+     * @return  {@code URL} object for reading the resource; {@code null} if
+     *          the resource could not be found, a {@code URL} could not be
+     *          constructed to locate the resource, the resource is in a package
+     *          that is not opened unconditionally, or access to the resource is
+     *          denied by the security manager.
      *
      * @since  1.2
      */
@@ -1483,14 +1510,22 @@
      * implementations should override this method to specify where to load
      * resources from.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules defined to this class loader.
+     * <p> For resources in named modules then the method must implement the
+     * rules for encapsulation specified in the {@code Module} {@link
+     * Module#getResourceAsStream getResourceAsStream} method. Additionally,
+     * it must not find non-"{@code .class}" resources in packages of named
+     * modules unless the package is {@link Module#isOpen(String) opened}
+     * unconditionally. </p>
      *
      * @param  name
      *         The resource name
      *
      * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
-     *          the resources
+     *          the resource. If no resources could  be found, the enumeration
+     *          will be empty. Resources for which a {@code URL} cannot be
+     *          constructed, are in a package that is not opened unconditionally,
+     *          or access to the resource is denied by the security manager,
+     *          are not returned in the enumeration.
      *
      * @throws  IOException
      *          If I/O errors occur
@@ -1498,7 +1533,7 @@
      * @since  1.2
      */
     protected Enumeration<URL> findResources(String name) throws IOException {
-        return java.util.Collections.emptyEnumeration();
+        return Collections.emptyEnumeration();
     }
 
     /**
@@ -1549,14 +1584,21 @@
      * classes.  This method locates the resource through the system class
      * loader (see {@link #getSystemClassLoader()}).
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally. </p>
      *
      * @param  name
      *         The resource name
      *
-     * @return  A {@link java.net.URL <tt>URL</tt>} object for reading the
-     *          resource, or <tt>null</tt> if the resource could not be found
+     * @return  A {@link java.net.URL <tt>URL</tt>} to the resource; {@code
+     *          null} if the resource could not be found, a URL could not be
+     *          constructed to locate the resource, the resource is in a package
+     *          that is not opened unconditionally or access to the resource is
+     *          denied by the security manager.
      *
      * @since  1.1
      */
@@ -1570,17 +1612,25 @@
      * {@link java.util.Enumeration <tt>Enumeration</tt>} of {@link
      * java.net.URL <tt>URL</tt>} objects.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
-     *
      * <p> The search order is described in the documentation for {@link
      * #getSystemResource(String)}.  </p>
      *
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally. </p>
+     *
      * @param  name
      *         The resource name
      *
-     * @return  An enumeration of resource {@link java.net.URL <tt>URL</tt>}
-     *          objects
+     * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
+     *          the resource. If no resources could  be found, the enumeration
+     *          will be empty. Resources for which a {@code URL} cannot be
+     *          constructed, are in a package that is not opened unconditionally,
+     *          or access to the resource is denied by the security manager,
+     *          are not returned in the enumeration.
      *
      * @throws  IOException
      *          If I/O errors occur
@@ -1596,17 +1646,24 @@
     /**
      * Returns an input stream for reading the specified resource.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
-     *
      * <p> The search order is described in the documentation for {@link
      * #getResource(String)}.  </p>
      *
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally. </p>
+     *
      * @param  name
      *         The resource name
      *
-     * @return  An input stream for reading the resource, or <tt>null</tt>
-     *          if the resource could not be found
+     * @return  An input stream for reading the resource; {@code null} if the
+     *          resource could not be found, the resource is in a package that
+     *          is not opened unconditionally, or access to the resource is
+     *          denied by the security manager.
+     *
      * @throws  NullPointerException If {@code name} is {@code null}
      *
      * @since  1.1
@@ -1626,14 +1683,20 @@
      * used to load classes.  This method locates the resource through the
      * system class loader (see {@link #getSystemClassLoader()}).
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally. </p>
      *
      * @param  name
      *         The resource name
      *
-     * @return  An input stream for reading the resource, or <tt>null</tt>
-     *          if the resource could not be found
+     * @return  An input stream for reading the resource; {@code null} if the
+     *          resource could not be found, the resource is in a package that
+     *          is not opened unconditionally, or access to the resource is
+     *          denied by the security manager.
      *
      * @since  1.1
      */
@@ -2719,33 +2782,7 @@
     private static native AssertionStatusDirectives retrieveDirectives();
 
 
-    /**
-     * Returns the ServiceCatalog for modules defined to this class loader
-     * or {@code null} if this class loader does not have a services catalog.
-     */
-    ServicesCatalog getServicesCatalog() {
-        return servicesCatalog;
-    }
-
-    /**
-     * Returns the ServiceCatalog for modules defined to this class loader,
-     * creating it if it doesn't already exist.
-     */
-    ServicesCatalog createOrGetServicesCatalog() {
-        ServicesCatalog catalog = servicesCatalog;
-        if (catalog == null) {
-            catalog = ServicesCatalog.create();
-            boolean set = trySetObjectField("servicesCatalog", catalog);
-            if (!set) {
-                // beaten by someone else
-                catalog = servicesCatalog;
-            }
-        }
-        return catalog;
-    }
-
-    // the ServiceCatalog for modules associated with this class loader.
-    private volatile ServicesCatalog servicesCatalog;
+    // -- Misc --
 
     /**
      * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s)
--- a/jdk/src/java.base/share/classes/java/lang/Deprecated.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Deprecated.java	Wed Jul 05 22:32:06 2017 +0200
@@ -40,6 +40,11 @@
  * annotation on a local variable declaration or on a parameter declaration
  * or a package declaration has no effect on the warnings issued by a compiler.
  *
+ * <p>When a module is deprecated, the use of that module in {@code
+ * requires}, but not in {@code exports} or {@code opens} clauses causes
+ * a warning to be issued. A module being deprecated does <em>not</em> cause
+ * warnings to be issued for uses of types within the module.
+ *
  * <p>This annotation type has a string-valued element {@code since}. The value
  * of this element indicates the version in which the annotated program element
  * was first deprecated.
@@ -74,7 +79,7 @@
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
+@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
 public @interface Deprecated {
     /**
      * Returns the version in which the annotated element became deprecated.
--- a/jdk/src/java.base/share/classes/java/lang/Iterable.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Iterable.java	Wed Jul 05 22:32:06 2017 +0200
@@ -53,10 +53,13 @@
     /**
      * Performs the given action for each element of the {@code Iterable}
      * until all elements have been processed or the action throws an
-     * exception.  Unless otherwise specified by the implementing class,
-     * actions are performed in the order of iteration (if an iteration order
-     * is specified).  Exceptions thrown by the action are relayed to the
+     * exception.  Actions are performed in the order of iteration, if that
+     * order is specified.  Exceptions thrown by the action are relayed to the
      * caller.
+     * <p>
+     * The behavior of this method is unspecified if the action performs
+     * side-effects that modify the underlying source of elements, unless an
+     * overriding class has specified a concurrent modification policy.
      *
      * @implSpec
      * <p>The default implementation behaves as if:
--- a/jdk/src/java.base/share/classes/java/lang/Package.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Package.java	Wed Jul 05 22:32:06 2017 +0200
@@ -398,10 +398,16 @@
         if (packageInfo == null) {
             // find package-info.class defined by loader
             String cn = packageName() + ".package-info";
-            PrivilegedAction<ClassLoader> pa = module()::getClassLoader;
+            Module module = module();
+            PrivilegedAction<ClassLoader> pa = module::getClassLoader;
             ClassLoader loader = AccessController.doPrivileged(pa);
-            Class<?> c = loader != null ? loader.loadLocalClass(cn)
-                                        : BootLoader.loadClassOrNull(cn);
+            Class<?> c;
+            if (loader != null) {
+                c = loader.loadClass(module, cn);
+            } else {
+                c = BootLoader.loadClass(module, cn);
+            }
+
             if (c != null) {
                 packageInfo = c;
             } else {
--- a/jdk/src/java.base/share/classes/java/lang/StringUTF16.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/StringUTF16.java	Wed Jul 05 22:32:06 2017 +0200
@@ -811,7 +811,9 @@
                 throw new NullPointerException();
             if (((a = array).length >> 1) >= (hi = fence) &&
                 (i = index) >= 0 && i < (index = hi)) {
-                do { action.accept(getChar(a, i)); } while (++i < hi);
+                do {
+                    action.accept(charAt(a, i));
+                } while (++i < hi);
             }
         }
 
@@ -819,8 +821,10 @@
         public boolean tryAdvance(IntConsumer action) {
             if (action == null)
                 throw new NullPointerException();
-            if (index >= 0 && index < fence) {
-                action.accept(getChar(array, index++));
+            int i = index;
+            if (i >= 0 && i < fence) {
+                action.accept(charAt(array, i));
+                index++;
                 return true;
             }
             return false;
@@ -860,8 +864,8 @@
 
             int midOneLess;
             // If the mid-point intersects a surrogate pair
-            if (Character.isLowSurrogate(getChar(array, mid)) &&
-                Character.isHighSurrogate(getChar(array, midOneLess = (mid -1)))) {
+            if (Character.isLowSurrogate(charAt(array, mid)) &&
+                Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) {
                 // If there is only one pair it cannot be split
                 if (lo >= midOneLess)
                     return null;
@@ -898,10 +902,10 @@
         // Advance one code point from the index, i, and return the next
         // index to advance from
         private static int advance(byte[] a, int i, int hi, IntConsumer action) {
-            char c1 = getChar(a, i++);
+            char c1 = charAt(a, i++);
             int cp = c1;
             if (Character.isHighSurrogate(c1) && i < hi) {
-                char c2 = getChar(a, i);
+                char c2 = charAt(a, i);
                 if (Character.isLowSurrogate(c2)) {
                     i++;
                     cp = Character.toCodePoint(c1, c2);
--- a/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java	Wed Jul 05 22:32:06 2017 +0200
@@ -35,6 +35,9 @@
  * a superset of the warnings suppressed in all containing elements.  For
  * example, if you annotate a class to suppress one warning and annotate a
  * method to suppress another, both warnings will be suppressed in the method.
+ * However, note that if a warning is suppressed in a {@code
+ * module-info} file, the suppression applies to elements within the
+ * file and <em>not</em> to types contained within the module.
  *
  * <p>As a matter of style, programmers should always use this annotation
  * on the most deeply nested element where it is effective.  If you want to
@@ -49,7 +52,7 @@
  * @jls 5.5.2 Checked Casts and Unchecked Casts
  * @jls 9.6.4.5 @SuppressWarnings
  */
-@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
 @Retention(RetentionPolicy.SOURCE)
 public @interface SuppressWarnings {
     /**
--- a/jdk/src/java.base/share/classes/java/lang/System.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/System.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,6 +38,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Executable;
 import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Module;
 import java.net.URL;
@@ -69,7 +70,6 @@
 import jdk.internal.logger.LocalizedLoggerWrapper;
 
 import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.ServicesCatalog;
 
 /**
  * The <code>System</code> class contains several useful class fields
@@ -1987,7 +1987,10 @@
 
     private static void setJavaLangAccess() {
         // Allow privileged classes outside of java.lang
-        SharedSecrets.setJavaLangAccess(new JavaLangAccess(){
+        SharedSecrets.setJavaLangAccess(new JavaLangAccess() {
+            public Method getMethodOrNull(Class<?> klass, String name, Class<?>... parameterTypes) {
+                return klass.getMethodOrNull(name, parameterTypes);
+            }
             public jdk.internal.reflect.ConstantPool getConstantPool(Class<?> klass) {
                 return klass.getConstantPool();
             }
@@ -2031,12 +2034,6 @@
             public Layer getBootLayer() {
                 return bootLayer;
             }
-            public ServicesCatalog getServicesCatalog(ClassLoader cl) {
-                return cl.getServicesCatalog();
-            }
-            public ServicesCatalog createOrGetServicesCatalog(ClassLoader cl) {
-                return cl.createOrGetServicesCatalog();
-            }
             public ConcurrentHashMap<?, ?> createOrGetClassLoaderValueMap(ClassLoader cl) {
                 return cl.createOrGetClassLoaderValueMap();
             }
--- a/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template	Wed Jul 05 22:32:06 2017 +0200
@@ -123,27 +123,25 @@
 
     /**
      * In case you were wondering this method is called by java -version.
-     * Sad that it prints to stderr; would be nicer if default printed on
-     * stdout.
      */
-    public static void print() {
-        print(System.err);
+    public static void print(boolean err) {
+        print(err, false);
     }
 
     /**
      * This is the same as print except that it adds an extra line-feed
      * at the end, typically used by the -showversion in the launcher
      */
-    public static void println() {
-        print(System.err);
-        System.err.println();
+    public static void println(boolean err) {
+        print(err, true);
     }
 
     /**
-     * Give a stream, it will print version info on it.
+     * Print version info.
      */
-    public static void print(PrintStream ps) {
+    private static void print(boolean err, boolean newln) {
         boolean isHeadless = false;
+        PrintStream ps = err ? System.err : System.out;
 
         /* Report that we're running headless if the property is true */
         String headless = System.getProperty("java.awt.headless");
@@ -152,10 +150,14 @@
         }
 
         /* First line: platform version. */
-        ps.println(launcher_name + " version \"" + java_version + "\"");
+        if (err) {
+            ps.println(launcher_name + " version \"" + java_version + "\"");
+        } else {
+            /* Use a format more in line with GNU conventions */
+            ps.println(launcher_name + " " + java_version);
+        }
 
         /* Second line: runtime version (ie, libraries). */
-
         String jdk_debug_level = System.getProperty("jdk.debug", "release");
         /* Debug level is not printed for "release" builds */
         if ("release".equals(jdk_debug_level)) {
--- a/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -37,10 +37,10 @@
  * <em>type contexts</em> , where annotations apply to types used in
  * declarations and expressions.
  *
- * <p>The constants {@link #ANNOTATION_TYPE} , {@link #CONSTRUCTOR} , {@link
- * #FIELD} , {@link #LOCAL_VARIABLE} , {@link #METHOD} , {@link #PACKAGE} ,
- * {@link #PARAMETER} , {@link #TYPE} , and {@link #TYPE_PARAMETER} correspond
- * to the declaration contexts in JLS 9.6.4.1.
+ * <p>The constants {@link #ANNOTATION_TYPE}, {@link #CONSTRUCTOR}, {@link
+ * #FIELD}, {@link #LOCAL_VARIABLE}, {@link #METHOD}, {@link #PACKAGE}, {@link
+ * #MODULE}, {@link #PARAMETER}, {@link #TYPE}, and {@link #TYPE_PARAMETER}
+ * correspond to the declaration contexts in JLS 9.6.4.1.
  *
  * <p>For example, an annotation whose type is meta-annotated with
  * {@code @Target(ElementType.FIELD)} may only be written as a modifier for a
@@ -107,5 +107,12 @@
      *
      * @since 1.8
      */
-    TYPE_USE
+    TYPE_USE,
+
+    /**
+     * Module declaration.
+     *
+     * @since 9
+     */
+    MODULE
 }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1147,12 +1147,14 @@
 
         static
         MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
-            // Do not use this function to inject calls into system classes.
+            // Code in the the boot layer should now be careful while creating method handles or
+            // functional interface instances created from method references to @CallerSensitive  methods,
+            // it needs to be ensured the handles or interface instances are kept safe and are not passed
+            // from the boot layer to untrusted code.
             if (hostClass == null
                 ||    (hostClass.isArray() ||
                        hostClass.isPrimitive() ||
-                       hostClass.getName().startsWith("java.") ||
-                       hostClass.getName().startsWith("sun."))) {
+                       hostClass.getName().startsWith("java.lang.invoke."))) {
                 throw new InternalError();  // does not happen, and should not anyway
             }
             // For simplicity, convert mh to a varargs-like method.
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Jul 05 22:32:06 2017 +0200
@@ -42,6 +42,7 @@
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
 import java.lang.reflect.ReflectPermission;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -142,6 +143,59 @@
     }
 
     /**
+     * Returns a {@link Lookup lookup object} with full capabilities to emulate all
+     * supported bytecode behaviors, including <a href="MethodHandles.Lookup.html#privacc">
+     * private access</a>, on a target class.
+     * This method checks that a caller, specified as a {@code Lookup} object, is allowed to
+     * do <em>deep reflection</em> on the target class. If {@code m1} is the module containing
+     * the {@link Lookup#lookupClass() lookup class}, and {@code m2} is the module containing
+     * the target class, then this check ensures that
+     * <ul>
+     *     <li>{@code m1} {@link Module#canRead reads} {@code m2}.</li>
+     *     <li>{@code m2} {@link Module#isOpen(String,Module) opens} the package containing
+     *     the target class to at least {@code m1}.</li>
+     *     <li>The lookup has the {@link Lookup#MODULE MODULE} lookup mode.</li>
+     * </ul>
+     * <p>
+     * If there is a security manager, its {@code checkPermission} method is called to
+     * check {@code ReflectPermission("suppressAccessChecks")}.
+     * @apiNote The {@code MODULE} lookup mode serves to authenticate that the lookup object
+     * was created by code in the caller module (or derived from a lookup object originally
+     * created by the caller). A lookup object with the {@code MODULE} lookup mode can be
+     * shared with trusted parties without giving away {@code PRIVATE} and {@code PACKAGE}
+     * access to the caller.
+     * @param targetClass the target class
+     * @param lookup the caller lookup object
+     * @return a lookup object for the target class, with private access
+     * @throws IllegalArgumentException if {@code targetClass} is a primitve type or array class
+     * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null}
+     * @throws IllegalAccessException if the access check specified above fails
+     * @throws SecurityException if denied by the security manager
+     * @since 9
+     */
+    public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+        if (targetClass.isPrimitive())
+            throw new IllegalArgumentException(targetClass + " is a primitive class");
+        if (targetClass.isArray())
+            throw new IllegalArgumentException(targetClass + " is an array class");
+        Module targetModule = targetClass.getModule();
+        Module callerModule = lookup.lookupClass().getModule();
+        if (callerModule != targetModule && targetModule.isNamed()) {
+            if (!callerModule.canRead(targetModule))
+                throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+            String pn = targetClass.getPackageName();
+            assert pn != null && pn.length() > 0 : "unnamed package cannot be in named module";
+            if (!targetModule.isOpen(pn, callerModule))
+                throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
+        }
+        if ((lookup.lookupModes() & Lookup.MODULE) == 0)
+            throw new IllegalAccessException("lookup does not have MODULE lookup mode");
+        return new Lookup(targetClass);
+    }
+
+    /**
      * Performs an unchecked "crack" of a
      * <a href="MethodHandleInfo.html#directmh">direct method handle</a>.
      * The result is as if the user had obtained a lookup object capable enough
@@ -1807,7 +1861,12 @@
             return callerClass;
         }
 
-        private boolean hasPrivateAccess() {
+        /**
+         * Returns {@code true} if this lookup has {@code PRIVATE} access.
+         * @return {@code true} if this lookup has {@code PRIVATE} acesss.
+         * @since 9
+         */
+        public boolean hasPrivateAccess() {
             return (allowedModes & PRIVATE) != 0;
         }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,14 +26,20 @@
 package java.lang.module;
 
 import java.io.PrintStream;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * The configuration that is the result of resolution or resolution with
@@ -46,14 +52,14 @@
  * dependences expressed by {@code requires} clauses.
  *
  * The <em>dependence graph</em> is augmented with edges that take account of
- * implicitly declared dependences ({@code requires public}) to create a
+ * implicitly declared dependences ({@code requires transitive}) to create a
  * <em>readability graph</em>. A {@code Configuration} encapsulates the
  * resulting graph of {@link ResolvedModule resolved modules}.
  *
  * <p> Suppose we have the following observable modules: </p>
  * <pre> {@code
  *     module m1 { requires m2; }
- *     module m2 { requires public m3; }
+ *     module m2 { requires transitive m3; }
  *     module m3 { }
  *     module m4 { }
  * } </pre>
@@ -70,8 +76,10 @@
  * <p> Resolution is an additive process. When computing the transitive closure
  * then the dependence relation may include dependences on modules in parent
  * configurations. The result is a <em>relative configuration</em> that is
- * relative to a parent configuration and where the readability graph may have
- * edges from modules in the configuration to modules in a parent configuration.
+ * relative to one or more parent configurations and where the readability graph
+ * may have edges from modules in the configuration to modules in parent
+ * configurations.
+ *
  * </p>
  *
  * <p> Suppose we have the following observable modules: </p>
@@ -96,9 +104,9 @@
  * <p> {@link ModuleDescriptor#isAutomatic() Automatic} modules receive special
  * treatment during resolution. Each automatic module is resolved so that it
  * reads all other modules in the configuration and all parent configurations.
- * Each automatic module is also resolved as if it {@code requires public} all
- * other automatic modules in the configuration (and all automatic modules in
- * parent configurations). </p>
+ * Each automatic module is also resolved as if it {@code requires transitive}
+ * all other automatic modules in the configuration (and all automatic modules
+ * in parent configurations). </p>
 
  * <h2><a name="servicebinding">Service binding</a></h2>
  *
@@ -171,54 +179,157 @@
     // @see Configuration#empty()
     private static final Configuration EMPTY_CONFIGURATION = new Configuration();
 
-    private final Configuration parent;
+    // parent configurations, in search order
+    private final List<Configuration> parents;
 
     private final Map<ResolvedModule, Set<ResolvedModule>> graph;
     private final Set<ResolvedModule> modules;
     private final Map<String, ResolvedModule> nameToModule;
 
     private Configuration() {
-        this.parent = null;
+        this.parents = Collections.emptyList();
         this.graph = Collections.emptyMap();
         this.modules = Collections.emptySet();
         this.nameToModule = Collections.emptyMap();
     }
 
-    private Configuration(Configuration parent,
+    private Configuration(List<Configuration> parents,
                           Resolver resolver,
                           boolean check)
     {
         Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check);
 
-        Map<String, ResolvedModule> nameToModule = new HashMap<>();
+        @SuppressWarnings(value = {"rawtypes", "unchecked"})
+        Entry<String, ResolvedModule>[] nameEntries
+            = (Entry<String, ResolvedModule>[])new Entry[g.size()];
+        ResolvedModule[] moduleArray = new ResolvedModule[g.size()];
+        int i = 0;
         for (ResolvedModule resolvedModule : g.keySet()) {
-            nameToModule.put(resolvedModule.name(), resolvedModule);
+            moduleArray[i] = resolvedModule;
+            nameEntries[i] = Map.entry(resolvedModule.name(), resolvedModule);
+            i++;
         }
 
-        this.parent = parent;
+        this.parents = Collections.unmodifiableList(parents);
         this.graph = g;
-        this.modules = Collections.unmodifiableSet(g.keySet());
-        this.nameToModule = Collections.unmodifiableMap(nameToModule);
+        this.modules = Set.of(moduleArray);
+        this.nameToModule = Map.ofEntries(nameEntries);
     }
 
 
     /**
      * Resolves a collection of root modules, with this configuration as its
-     * parent, to create a new configuration.
+     * parent, to create a new configuration. This method works exactly as
+     * specified by the static {@link
+     * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires}
+     * method when invoked with this configuration as the parent. In other words,
+     * if this configuration is {@code cf} then this method is equivalent to
+     * invoking:
+     * <pre> {@code
+     *     Configuration.resolveRequires(before, List.of(cf), after, roots);
+     * }</pre>
+     *
+     * @param  before
+     *         The <em>before</em> module finder to find modules
+     * @param  after
+     *         The <em>after</em> module finder to locate modules when a
+     *         module cannot be located by the {@code before} module finder
+     *         and the module is not in this configuration
+     * @param  roots
+     *         The possibly-empty collection of module names of the modules
+     *         to resolve
+     *
+     * @return The configuration that is the result of resolving the given
+     *         root modules
+     *
+     * @throws ResolutionException
+     *         If resolution or the post-resolution checks fail
+     * @throws SecurityException
+     *         If locating a module is denied by the security manager
+     */
+    public Configuration resolveRequires(ModuleFinder before,
+                                         ModuleFinder after,
+                                         Collection<String> roots)
+    {
+        return resolveRequires(before, List.of(this), after, roots);
+    }
+
+
+    /**
+     * Resolves a collection of root modules, with service binding, and with
+     * this configuration as its parent, to create a new configuration.
+     * This method works exactly as specified by the static {@link
+     * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection)
+     * resolveRequiresAndUses} method when invoked with this configuration
+     * as the parent. In other words, if this configuration is {@code cf} then
+     * this method is equivalent to invoking:
+     * <pre> {@code
+     *     Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots);
+     * }</pre>
+     *
+     *
+     * @param  before
+     *         The <em>before</em> module finder to find modules
+     * @param  after
+     *         The <em>after</em> module finder to locate modules when not
+     *         located by the {@code before} module finder and this
+     *         configuration
+     * @param  roots
+     *         The possibly-empty collection of module names of the modules
+     *         to resolve
+     *
+     * @return The configuration that is the result of resolving the given
+     *         root modules
+     *
+     * @throws ResolutionException
+     *         If resolution or the post-resolution checks fail
+     * @throws SecurityException
+     *         If locating a module is denied by the security manager
+     */
+    public Configuration resolveRequiresAndUses(ModuleFinder before,
+                                                ModuleFinder after,
+                                                Collection<String> roots)
+    {
+        return resolveRequiresAndUses(before, List.of(this), after, roots);
+    }
+
+
+    /**
+     * Resolves a collection of root modules, with service binding, and with
+     * the empty configuration as its parent. The post resolution checks
+     * are optionally run.
+     *
+     * This method is used to create the configuration for the boot layer.
+     */
+    static Configuration resolveRequiresAndUses(ModuleFinder finder,
+                                                Collection<String> roots,
+                                                boolean check,
+                                                PrintStream traceOutput)
+    {
+        List<Configuration> parents = List.of(empty());
+        Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
+        resolver.resolveRequires(roots).resolveUses();
+
+        return new Configuration(parents, resolver, check);
+    }
+
+
+    /**
+     * Resolves a collection of root modules to create a configuration.
      *
      * <p> Each root module is located using the given {@code before} module
      * finder. If a module is not found then it is located in the parent
      * configuration as if by invoking the {@link #findModule(String)
-     * findModule} method. If not found then the module is located using the
-     * given {@code after} module finder. The same search order is used to
-     * locate transitive dependences. Root modules or dependences that are
-     * located in a parent configuration are resolved no further and are not
-     * included in the resulting configuration. </p>
+     * findModule} method on each parent in iteration order. If not found then
+     * the module is located using the given {@code after} module finder. The
+     * same search order is used to locate transitive dependences. Root modules
+     * or dependences that are located in a parent configuration are resolved
+     * no further and are not included in the resulting configuration. </p>
      *
      * <p> When all modules have been resolved then the resulting dependency
      * graph is checked to ensure that it does not contain cycles. A
-     * readability graph is constructed and then, in conjunction with the
-     * module exports and service use, checked for consistency. </p>
+     * readability graph is constructed and in conjunction with the module
+     * exports and service use, checked for consistency. </p>
      *
      * <p> Resolution and the (post-resolution) consistency checks may fail for
      * following reasons: </p>
@@ -262,6 +373,8 @@
      *
      * @param  before
      *         The <em>before</em> module finder to find modules
+     * @param  parents
+     *         The list parent configurations in search order
      * @param  after
      *         The <em>after</em> module finder to locate modules when not
      *         located by the {@code before} module finder or in parent
@@ -274,31 +387,37 @@
      *         root modules
      *
      * @throws ResolutionException
-     *         If resolution or the post-resolution checks fail for any of the
-     *         reasons listed
+     *         If resolution or the post-resolution checks fail
+     * @throws IllegalArgumentException
+     *         If the list of parents is empty
      * @throws SecurityException
      *         If locating a module is denied by the security manager
      */
-    public Configuration resolveRequires(ModuleFinder before,
-                                         ModuleFinder after,
-                                         Collection<String> roots)
+    public static Configuration resolveRequires(ModuleFinder before,
+                                                List<Configuration> parents,
+                                                ModuleFinder after,
+                                                Collection<String> roots)
     {
         Objects.requireNonNull(before);
         Objects.requireNonNull(after);
         Objects.requireNonNull(roots);
 
-        Resolver resolver = new Resolver(before, this, after, null);
+        List<Configuration> parentList = new ArrayList<>(parents);
+        if (parentList.isEmpty())
+            throw new IllegalArgumentException("'parents' is empty");
+
+        Resolver resolver = new Resolver(before, parentList, after, null);
         resolver.resolveRequires(roots);
 
-        return new Configuration(this, resolver, true);
+        return new Configuration(parentList, resolver, true);
     }
 
-
     /**
-     * Resolves a collection of root modules, with service binding, and with
-     * this configuration as its parent, to create a new configuration.
+     * Resolves a collection of root modules, with service binding, to create
+     * configuration.
      *
-     * <p> This method works exactly as specified by {@link #resolveRequires
+     * <p> This method works exactly as specified by {@link
+     * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection)
      * resolveRequires} except that the graph of resolved modules is augmented
      * with modules induced by the service-use dependence relation. </p>
      *
@@ -319,6 +438,8 @@
      *
      * @param  before
      *         The <em>before</em> module finder to find modules
+     * @param  parents
+     *         The list parent configurations in search order
      * @param  after
      *         The <em>after</em> module finder to locate modules when not
      *         located by the {@code before} module finder or in parent
@@ -331,51 +452,35 @@
      *         root modules
      *
      * @throws ResolutionException
-     *         If resolution or the post-resolution checks fail for any of the
-     *         reasons listed
+     *         If resolution or the post-resolution checks fail
+     * @throws IllegalArgumentException
+     *         If the list of parents is empty
      * @throws SecurityException
      *         If locating a module is denied by the security manager
      */
-    public Configuration resolveRequiresAndUses(ModuleFinder before,
-                                                ModuleFinder after,
-                                                Collection<String> roots)
+    public static Configuration resolveRequiresAndUses(ModuleFinder before,
+                                                       List<Configuration> parents,
+                                                       ModuleFinder after,
+                                                       Collection<String> roots)
     {
         Objects.requireNonNull(before);
         Objects.requireNonNull(after);
         Objects.requireNonNull(roots);
 
-        Resolver resolver = new Resolver(before, this, after, null);
+        List<Configuration> parentList = new ArrayList<>(parents);
+        if (parentList.isEmpty())
+            throw new IllegalArgumentException("'parents' is empty");
+
+        Resolver resolver = new Resolver(before, parentList, after, null);
         resolver.resolveRequires(roots).resolveUses();
 
-        return new Configuration(this, resolver, true);
+        return new Configuration(parentList, resolver, true);
     }
 
 
     /**
-     * Resolves a collection of root modules, with service binding, and with
-     * the empty configuration as its parent. The post resolution checks
-     * are optionally run.
-     *
-     * This method is used to create the configuration for the boot layer.
-     */
-    static Configuration resolveRequiresAndUses(ModuleFinder finder,
-                                                Collection<String> roots,
-                                                boolean check,
-                                                PrintStream traceOutput)
-    {
-        Configuration parent = empty();
-
-        Resolver resolver
-            = new Resolver(finder, parent, ModuleFinder.of(), traceOutput);
-        resolver.resolveRequires(roots).resolveUses();
-
-        return new Configuration(parent, resolver, check);
-    }
-
-
-    /**
-     * Returns the <em>empty</em> configuration. The empty configuration does
-     * not contain any modules and does not have a parent.
+     * Returns the <em>empty</em> configuration. There are no modules in the
+     * empty configuration. It has no parents.
      *
      * @return The empty configuration
      */
@@ -385,13 +490,14 @@
 
 
     /**
-     * Returns this configuration's parent unless this is the {@linkplain #empty
-     * empty configuration}, which has no parent.
+     * Returns an unmodifiable list of this configuration's parents, in search
+     * order. If this is the {@linkplain #empty empty configuration} then an
+     * empty list is returned.
      *
-     * @return This configuration's parent
+     * @return A possibly-empty unmodifiable list of this parent configurations
      */
-    public Optional<Configuration> parent() {
-        return Optional.ofNullable(parent);
+    public List<Configuration> parents() {
+        return parents;
     }
 
 
@@ -408,23 +514,35 @@
 
     /**
      * Finds a resolved module in this configuration, or if not in this
-     * configuration, the {@linkplain #parent parent} configurations.
+     * configuration, the {@linkplain #parents parent} configurations.
+     * Finding a module in parent configurations is equivalent to invoking
+     * {@code findModule} on each parent, in search order, until the module
+     * is found or all parents have been searched. In a <em>tree of
+     * configurations</em> then this is equivalent to a depth-first search.
      *
      * @param  name
      *         The module name of the resolved module to find
      *
      * @return The resolved module with the given name or an empty {@code
      *         Optional} if there isn't a module with this name in this
-     *         configuration or any parent configuration
+     *         configuration or any parent configurations
      */
     public Optional<ResolvedModule> findModule(String name) {
         Objects.requireNonNull(name);
-        if (parent == null)
-            return Optional.empty();
         ResolvedModule m = nameToModule.get(name);
         if (m != null)
             return Optional.of(m);
-        return parent().flatMap(x -> x.findModule(name));
+
+        if (!parents.isEmpty()) {
+            return configurations()
+                    .skip(1)  // skip this configuration
+                    .map(cf -> cf.nameToModule)
+                    .filter(map -> map.containsKey(name))
+                    .map(map -> map.get(name))
+                    .findFirst();
+        }
+
+        return Optional.empty();
     }
 
 
@@ -444,9 +562,46 @@
     }
 
     /**
+     * Returns an ordered stream of configurations. The first element is this
+     * configuration, the remaining elements are the parent configurations
+     * in DFS order.
+     *
+     * @implNote For now, the assumption is that the number of elements will
+     * be very low and so this method does not use a specialized spliterator.
+     */
+    Stream<Configuration> configurations() {
+        List<Configuration> allConfigurations = this.allConfigurations;
+        if (allConfigurations == null) {
+            allConfigurations = new ArrayList<>();
+            Set<Configuration> visited = new HashSet<>();
+            Deque<Configuration> stack = new ArrayDeque<>();
+            visited.add(this);
+            stack.push(this);
+            while (!stack.isEmpty()) {
+                Configuration layer = stack.pop();
+                allConfigurations.add(layer);
+
+                // push in reverse order
+                for (int i = layer.parents.size() - 1; i >= 0; i--) {
+                    Configuration parent = layer.parents.get(i);
+                    if (!visited.contains(parent)) {
+                        visited.add(parent);
+                        stack.push(parent);
+                    }
+                }
+            }
+            this.allConfigurations = Collections.unmodifiableList(allConfigurations);
+        }
+        return allConfigurations.stream();
+    }
+
+    private volatile List<Configuration> allConfigurations;
+
+
+    /**
      * Returns a string describing this configuration.
      *
-     * @return A string describing this configuration
+     * @return A possibly empty string describing this configuration
      */
     @Override
     public String toString() {
--- a/jdk/src/java.base/share/classes/java/lang/module/Dependence.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.lang.module;
-
-import java.util.*;
-import java.util.stream.*;
-
-
-class Dependence {
-
-    private Dependence() { }
-
-    static <T> Stream<String> toStringStream(Set<T> s) {
-        return s.stream().map(e -> e.toString().toLowerCase());
-    }
-
-    static <M> String toString(Set<M> mods, String what) {
-        return (Stream.concat(toStringStream(mods), Stream.of(what)))
-                      .collect(Collectors.joining(" "));
-    }
-
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Wed Jul 05 22:32:06 2017 +0200
@@ -45,6 +45,8 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static jdk.internal.module.Checks.*;
 import static java.util.Objects.*;
@@ -57,9 +59,11 @@
  * A module descriptor.
  *
  * <p> A {@code ModuleDescriptor} is typically created from the binary form
- * of a module declaration. The associated {@link ModuleDescriptor.Builder}
- * class can also be used to create a {@code ModuleDescriptor} from its
- * components. </p>
+ * of a module declaration. Alternatively, the {@link ModuleDescriptor.Builder}
+ * class can be used to create a {@code ModuleDescriptor} from its components.
+ * The {@link #module module}, {@link #openModule openModule}, and {@link
+ * #automaticModule automaticModule} methods create builders for building
+ * different kinds of modules. </p>
  *
  * <p> {@code ModuleDescriptor} objects are immutable and safe for use by
  * multiple concurrent threads.</p>
@@ -95,7 +99,13 @@
              * module</i> to have an implicitly declared dependence on the module
              * named by the {@code Requires}.
              */
-            PUBLIC,
+            TRANSITIVE,
+
+            /**
+             * The dependence is mandatory in the static phase, during compilation,
+             * but is optional in the dynamic phase, during execution.
+             */
+            STATIC,
 
             /**
              * The dependence was not explicitly or implicitly declared in the
@@ -115,16 +125,18 @@
         private final String name;
 
         private Requires(Set<Modifier> ms, String mn) {
-            this(ms, mn, true);
+            if (ms.isEmpty()) {
+                ms = Collections.emptySet();
+            } else {
+                ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
+            }
+            this.mods = ms;
+            this.name = mn;
         }
-        private Requires(Set<Modifier> ms, String mn, boolean check) {
-            if (ms == null || ms.isEmpty()) {
-                mods = Collections.emptySet();
-            } else {
-                mods = check ? Collections.unmodifiableSet(EnumSet.copyOf(ms))
-                             : ms;
-            }
-            this.name = check ? requireModuleName(mn) : mn;
+
+        private Requires(Set<Modifier> ms, String mn, boolean unused) {
+            this.mods = ms;
+            this.name = mn;
         }
 
         /**
@@ -223,9 +235,8 @@
          */
         @Override
         public String toString() {
-            return Dependence.toString(mods, name);
+            return ModuleDescriptor.toString(mods, name);
         }
-
     }
 
 
@@ -239,36 +250,61 @@
 
     public final static class Exports {
 
+        /**
+         * A modifier on a module export.
+         *
+         * @since 9
+         */
+        public static enum Modifier {
+
+            /**
+             * The export was not explicitly or implicitly declared in the
+             * source of the module declaration.
+             */
+            SYNTHETIC,
+
+            /**
+             * The export was implicitly declared in the source of the module
+             * declaration.
+             */
+            MANDATED;
+
+        }
+
+        private final Set<Modifier> mods;
         private final String source;
         private final Set<String> targets;  // empty if unqualified export
 
         /**
-         * Constructs a qualified export.
+         * Constructs an export
          */
-        private Exports(String source, Set<String> targets) {
-            this(source, targets, true);
+        private Exports(Set<Modifier> ms, String source, Set<String> targets) {
+            if (ms.isEmpty()) {
+                ms = Collections.emptySet();
+            } else {
+                ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
+            }
+            this.mods = ms;
+            this.source = source;
+            this.targets = emptyOrUnmodifiableSet(targets);
         }
 
-        private Exports(String source, Set<String> targets, boolean check) {
-            this.source = check ? requirePackageName(source) : source;
-            targets = check ? Collections.unmodifiableSet(new HashSet<>(targets))
-                            : Collections.unmodifiableSet(targets);
-            if (targets.isEmpty())
-                throw new IllegalArgumentException("Empty target set");
-            if (check)
-                targets.stream().forEach(Checks::requireModuleName);
+        private Exports(Set<Modifier> ms,
+                        String source,
+                        Set<String> targets,
+                        boolean unused) {
+            this.mods = ms;
+            this.source = source;
             this.targets = targets;
         }
 
         /**
-         * Constructs an unqualified export.
+         * Returns the set of modifiers.
+         *
+         * @return A possibly-empty unmodifiable set of modifiers
          */
-        private Exports(String source) {
-            this(source, true);
-        }
-        private Exports(String source, boolean check) {
-            this.source = check ? requirePackageName(source) : source;
-            this.targets = Collections.emptySet();
+        public Set<Modifier> modifiers() {
+            return mods;
         }
 
         /**
@@ -304,25 +340,27 @@
         /**
          * Computes a hash code for this module export.
          *
-         * <p> The hash code is based upon the package name, and for a
-         * qualified export, the set of modules names to which the package
-         * is exported. It satisfies the general contract of the {@link
-         * Object#hashCode Object.hashCode} method.
+         * <p> The hash code is based upon the modifiers, the package name,
+         * and for a qualified export, the set of modules names to which the
+         * package is exported. It satisfies the general contract of the
+         * {@link Object#hashCode Object.hashCode} method.
          *
          * @return The hash-code value for this module export
          */
         @Override
         public int hashCode() {
-            return hash(source, targets);
+            int hash = mods.hashCode();
+            hash = hash * 43 + source.hashCode();
+            return hash * 43 + targets.hashCode();
         }
 
         /**
          * Tests this module export for equality with the given object.
          *
          * <p> If the given object is not an {@code Exports} then this method
-         * returns {@code false}. Two module exports objects are equal if the
-         * package names are equal and the set of target module names is equal.
-         * </p>
+         * returns {@code false}. Two module exports objects are equal if their
+         * set of modifiers is equal, the package names are equal and the set
+         * of target module names is equal. </p>
          *
          * <p> This method satisfies the general contract of the {@link
          * java.lang.Object#equals(Object) Object.equals} method. </p>
@@ -338,8 +376,9 @@
             if (!(ob instanceof Exports))
                 return false;
             Exports other = (Exports)ob;
-            return Objects.equals(this.source, other.source) &&
-                Objects.equals(this.targets, other.targets);
+            return Objects.equals(this.mods, other.mods)
+                    && Objects.equals(this.source, other.source)
+                    && Objects.equals(this.targets, other.targets);
         }
 
         /**
@@ -349,15 +388,177 @@
          */
         @Override
         public String toString() {
+            String s = ModuleDescriptor.toString(mods, source);
             if (targets.isEmpty())
-                return source;
+                return s;
             else
-                return source + " to " + targets;
+                return s + " to " + targets;
+        }
+    }
+
+
+    /**
+     * <p> Represents a module <em>opens</em> directive, may be qualified or
+     * unqualified. </p>
+     *
+     * <p> The <em>opens</em> directive in a module declaration declares a
+     * package to be open to allow all types in the package, and all their
+     * members, not just public types and their public members to be reflected
+     * on by APIs that support private access or a way to bypass or suppress
+     * default Java language access control checks. </p>
+     *
+     * @see ModuleDescriptor#opens()
+     * @since 9
+     */
+
+    public final static class Opens {
+
+        /**
+         * A modifier on a module <em>opens</em> directive.
+         *
+         * @since 9
+         */
+        public static enum Modifier {
+
+            /**
+             * The opens was not explicitly or implicitly declared in the
+             * source of the module declaration.
+             */
+            SYNTHETIC,
+
+            /**
+             * The opens was implicitly declared in the source of the module
+             * declaration.
+             */
+            MANDATED;
+
+        }
+
+        private final Set<Modifier> mods;
+        private final String source;
+        private final Set<String> targets;  // empty if unqualified export
+
+        /**
+         * Constructs an Opens
+         */
+        private Opens(Set<Modifier> ms, String source, Set<String> targets) {
+            if (ms.isEmpty()) {
+                ms = Collections.emptySet();
+            } else {
+                ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
+            }
+            this.mods = ms;
+            this.source = source;
+            this.targets = emptyOrUnmodifiableSet(targets);
+        }
+
+        private Opens(Set<Modifier> ms,
+                      String source,
+                      Set<String> targets,
+                      boolean unused) {
+            this.mods = ms;
+            this.source = source;
+            this.targets = targets;
+        }
+
+        /**
+         * Returns the set of modifiers.
+         *
+         * @return A possibly-empty unmodifiable set of modifiers
+         */
+        public Set<Modifier> modifiers() {
+            return mods;
         }
 
+        /**
+         * Returns {@code true} if this is a qualified opens.
+         *
+         * @return {@code true} if this is a qualified opens
+         */
+        public boolean isQualified() {
+            return !targets.isEmpty();
+        }
+
+        /**
+         * Returns the package name.
+         *
+         * @return The package name
+         */
+        public String source() {
+            return source;
+        }
+
+        /**
+         * For a qualified opens, returns the non-empty and immutable set
+         * of the module names to which the package is open. For an
+         * unqualified opens, returns an empty set.
+         *
+         * @return The set of target module names or for an unqualified
+         *         opens, an empty set
+         */
+        public Set<String> targets() {
+            return targets;
+        }
+
+        /**
+         * Computes a hash code for this module opens.
+         *
+         * <p> The hash code is based upon the modifiers, the package name,
+         * and for a qualified opens, the set of modules names to which the
+         * package is opened. It satisfies the general contract of the
+         * {@link Object#hashCode Object.hashCode} method.
+         *
+         * @return The hash-code value for this module opens
+         */
+        @Override
+        public int hashCode() {
+            int hash = mods.hashCode();
+            hash = hash * 43 + source.hashCode();
+            return hash * 43 + targets.hashCode();
+        }
+
+        /**
+         * Tests this module opens for equality with the given object.
+         *
+         * <p> If the given object is not an {@code Opens} then this method
+         * returns {@code false}. Two {@code Opens} objects are equal if their
+         * set of modifiers is equal, the package names are equal and the set
+         * of target module names is equal. </p>
+         *
+         * <p> This method satisfies the general contract of the {@link
+         * java.lang.Object#equals(Object) Object.equals} method. </p>
+         *
+         * @param   ob
+         *          the object to which this object is to be compared
+         *
+         * @return  {@code true} if, and only if, the given object is a module
+         *          dependence that is equal to this module dependence
+         */
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof Opens))
+                return false;
+            Opens other = (Opens)ob;
+            return Objects.equals(this.mods, other.mods)
+                    && Objects.equals(this.source, other.source)
+                    && Objects.equals(this.targets, other.targets);
+        }
+
+        /**
+         * Returns a string describing module opens.
+         *
+         * @return A string describing module opens
+         */
+        @Override
+        public String toString() {
+            String s = ModuleDescriptor.toString(mods, source);
+            if (targets.isEmpty())
+                return s;
+            else
+                return s + " to " + targets;
+        }
     }
 
-
 
     /**
      * <p> A service that a module provides one or more implementations of. </p>
@@ -369,21 +570,15 @@
     public final static class Provides {
 
         private final String service;
-        private final Set<String> providers;
+        private final List<String> providers;
 
-        private Provides(String service, Set<String> providers) {
-            this(service, providers, true);
+        private Provides(String service, List<String> providers) {
+            this.service = service;
+            this.providers = Collections.unmodifiableList(providers);
         }
 
-        private Provides(String service, Set<String> providers, boolean check) {
-            this.service = check ? requireServiceTypeName(service) : service;
-            providers = check
-                ? Collections.unmodifiableSet(new LinkedHashSet<>(providers))
-                : Collections.unmodifiableSet(providers);
-            if (providers.isEmpty())
-                throw new IllegalArgumentException("Empty providers set");
-            if (check)
-                providers.forEach(Checks::requireServiceProviderName);
+        private Provides(String service, List<String> providers, boolean unused) {
+            this.service = service;
             this.providers = providers;
         }
 
@@ -395,12 +590,13 @@
         public String service() { return service; }
 
         /**
-         * Returns the set of the fully qualified class names of the providers.
+         * Returns the list of the fully qualified class names of the providers
+         * or provider factories.
          *
-         * @return A non-empty and unmodifiable set of the fully qualified class
-         *         names of the providers.
+         * @return A non-empty and unmodifiable list of the fully qualified class
+         *         names of the providers or provider factories
          */
-        public Set<String> providers() { return providers; }
+        public List<String> providers() { return providers; }
 
         /**
          * Computes a hash code for this provides.
@@ -413,7 +609,7 @@
          */
         @Override
         public int hashCode() {
-            return hash(service, providers);
+            return service.hashCode() * 43 + providers.hashCode();
         }
 
         /**
@@ -421,7 +617,7 @@
          *
          * <p> If the given object is not a {@code Provides} then this method
          * returns {@code false}. Two {@code Provides} objects are equal if the
-         * service type is equal and the set of providers is equal. </p>
+         * service type is equal and the list of providers is equal. </p>
          *
          * <p> This method satisfies the general contract of the {@link
          * java.lang.Object#equals(Object) Object.equals} method. </p>
@@ -774,10 +970,7 @@
 
     // From module declarations
     private final String name;
-    private final Set<Requires> requires;
-    private final Set<Exports> exports;
-    private final Set<String> uses;
-    private final Map<String, Provides> provides;
+    private final boolean open;
 
     // Indicates if synthesised for a JAR file found on the module path
     private final boolean automatic;
@@ -785,6 +978,12 @@
     // Not generated from a module-info.java
     private final boolean synthetic;
 
+    private final Set<Requires> requires;
+    private final Set<Exports> exports;
+    private final Set<Opens> opens;
+    private final Set<String> uses;
+    private final Set<Provides> provides;
+
     // "Extended" information, added post-compilation by tools
     private final Version version;
     private final String mainClass;
@@ -796,12 +995,14 @@
 
 
     private ModuleDescriptor(String name,
+                             boolean open,
                              boolean automatic,
                              boolean synthetic,
-                             Map<String, Requires> requires,
+                             Set<Requires> requires,
+                             Set<Exports> exports,
+                             Set<Opens> opens,
                              Set<String> uses,
-                             Map<String, Exports> exports,
-                             Map<String, Provides> provides,
+                             Set<Provides> provides,
                              Version version,
                              String mainClass,
                              String osName,
@@ -812,31 +1013,24 @@
     {
 
         this.name = name;
+        this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
 
-        Set<Requires> rqs = new HashSet<>(requires.values());
-        assert (rqs.stream().map(Requires::name).sorted().distinct().count()
-                == rqs.size())
-            : "Module " + name + " has duplicate requires";
-        this.requires = emptyOrUnmodifiableSet(rqs);
+        assert (requires.stream().map(Requires::name).distinct().count()
+                == requires.size());
+        this.requires = emptyOrUnmodifiableSet(requires);
 
-        Set<Exports> exs = new HashSet<>(exports.values());
-        assert (exs.stream().map(Exports::source).sorted().distinct().count()
-                == exs.size())
-            : "Module " + name + " has duplicate exports";
-        this.exports = emptyOrUnmodifiableSet(exs);
-
+        this.exports = emptyOrUnmodifiableSet(exports);
+        this.opens = emptyOrUnmodifiableSet(opens);
         this.uses = emptyOrUnmodifiableSet(uses);
-        this.provides = emptyOrUnmodifiableMap(provides);
-
+        this.provides = emptyOrUnmodifiableSet(provides);
         this.version = version;
         this.mainClass = mainClass;
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
         this.hashes = hashes;
-
         this.packages = emptyOrUnmodifiableSet(packages);
     }
 
@@ -845,11 +1039,13 @@
      */
     ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
         this.name = md.name;
+        this.open = md.open;
         this.automatic = md.automatic;
         this.synthetic = md.synthetic;
 
         this.requires = md.requires;
         this.exports = md.exports;
+        this.opens = md.opens;
         this.uses = md.uses;
         this.provides = md.provides;
 
@@ -866,38 +1062,44 @@
     }
 
     /**
-     * Creates a module descriptor from its components. This method is intended
-     * for use by the jlink plugin.
+     * Creates a module descriptor from its components.
+     * The arguments are pre-validated and sets are unmodifiable sets.
      */
     ModuleDescriptor(String name,
+                     boolean open,
                      boolean automatic,
                      boolean synthetic,
                      Set<Requires> requires,
+                     Set<Exports> exports,
+                     Set<Opens> opens,
                      Set<String> uses,
-                     Set<Exports> exports,
-                     Map<String, Provides> provides,
+                     Set<Provides> provides,
                      Version version,
                      String mainClass,
                      String osName,
                      String osArch,
                      String osVersion,
                      Set<String> packages,
-                     ModuleHashes hashes) {
+                     ModuleHashes hashes,
+                     int hashCode,
+                     boolean unused) {
         this.name = name;
+        this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
-        this.requires = Collections.unmodifiableSet(requires);
-        this.exports = Collections.unmodifiableSet(exports);
-        this.uses = Collections.unmodifiableSet(uses);
-        this.provides = Collections.unmodifiableMap(provides);
-        this.packages = Collections.unmodifiableSet(packages);
-
+        this.requires = requires;
+        this.exports = exports;
+        this.opens = opens;
+        this.uses = uses;
+        this.provides = provides;
+        this.packages = packages;
         this.version = version;
         this.mainClass = mainClass;
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
         this.hashes = hashes;
+        this.hash = hashCode;
     }
 
     /**
@@ -910,6 +1112,19 @@
     }
 
     /**
+     * <p> Returns {@code true} if this is an open module. </p>
+     *
+     * <p> An open module does not declare any open packages (the {@link #opens()
+     * opens} method returns an empty set) but the resulting module is treated
+     * as if all packages are open. </p>
+     *
+     * @return  {@code true} if this is an open module
+     */
+    public boolean isOpen() {
+        return open;
+    }
+
+    /**
      * <p> Returns {@code true} if this is an automatic module. </p>
      *
      * <p> An automatic module is defined implicitly rather than explicitly
@@ -933,8 +1148,6 @@
      *
      * @return  {@code true} if this module descriptor was not generated by
      *          an explicit or implicit module declaration
-     *
-     * @jvms 4.7.8 The {@code Synthetic} Attribute
      */
     public boolean isSynthetic() {
         return synthetic;
@@ -950,6 +1163,33 @@
     }
 
     /**
+     * <p> The module exports. </p>
+     *
+     * @return  A possibly-empty unmodifiable set of exported packages
+     */
+    public Set<Exports> exports() {
+        return exports;
+    }
+
+    /**
+     * <p> The module <em>opens</em> directives. </p>
+     *
+     * <p> Each {@code Opens} object in the set represents a package (and
+     * the set of target module names when qualified) where all types in the
+     * package, and all their members, not just public types and their public
+     * members, can be reflected on when using APIs that bypass or suppress
+     * default Java language access control checks. </p>
+     *
+     * <p> This method returns an empty set when invoked on {@link #isOpen()
+     * open} module. </p>
+     *
+     * @return  A possibly-empty unmodifiable set of open packages
+     */
+    public Set<Opens> opens() {
+        return opens;
+    }
+
+    /**
      * <p> The service dependences of this module. </p>
      *
      * @return  A possibly-empty unmodifiable set of the fully qualified class
@@ -962,24 +1202,14 @@
     /**
      * <p> The services that this module provides. </p>
      *
-     * @return The possibly-empty unmodifiable map of the services that this
-     *         module provides. The map key is fully qualified class name of
-     *         the service type.
+     * @return The possibly-empty unmodifiable set of the services that this
+     *         module provides
      */
-    public Map<String, Provides> provides() {
+    public Set<Provides> provides() {
         return provides;
     }
 
     /**
-     * <p> The module exports. </p>
-     *
-     * @return  A possibly-empty unmodifiable set of exported packages
-     */
-    public Set<Exports> exports() {
-        return exports;
-    }
-
-    /**
      * Returns this module's version.
      *
      * @return This module's version
@@ -1046,22 +1276,9 @@
     }
 
     /**
-     * Returns the names of the packages defined in, but not exported by, this
-     * module.
+     * Returns the names of all packages in this module.
      *
-     * @return A possibly-empty unmodifiable set of the concealed packages
-     */
-    public Set<String> conceals() {
-        Set<String> conceals = new HashSet<>(packages);
-        exports.stream().map(Exports::source).forEach(conceals::remove);
-        return emptyOrUnmodifiableSet(conceals);
-    }
-
-    /**
-     * Returns the names of all the packages defined in this module, whether
-     * exported or concealed.
-     *
-     * @return A possibly-empty unmodifiable set of the all packages
+     * @return A possibly-empty unmodifiable set of all packages in the module
      */
     public Set<String> packages() {
         return packages;
@@ -1078,31 +1295,39 @@
     /**
      * A builder used for building {@link ModuleDescriptor} objects.
      *
-     * <p> Example usage: </p>
+     * <p> {@code ModuleDescriptor} defines the {@link #module module}, {@link
+     * #openModule openModule}, and {@link #automaticModule automaticModule}
+     * methods to create builders for building different kinds of modules. </p>
      *
-     * <pre>{@code
-     *     ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1")
+     * <p> Example usage: </p>
+     * <pre>{@code    ModuleDescriptor descriptor = ModuleDescriptor.module("m1")
+     *         .exports("p")
      *         .requires("m2")
-     *         .exports("p")
      *         .build();
      * }</pre>
      *
-     * @apiNote A {@code Builder} cannot be used to create an {@link
-     * ModuleDescriptor#isAutomatic() automatic} or a {@link
-     * ModuleDescriptor#isSynthetic() synthetic} module.
+     * @apiNote A {@code Builder} checks the components and invariants as
+     * components are added to the builder. The rational for this is to detect
+     * errors as early as possible and not defer all validation to the
+     * {@link #build build} method. A {@code Builder} cannot be used to create
+     * a {@link ModuleDescriptor#isSynthetic() synthetic} module.
      *
      * @since 9
      */
     public static final class Builder {
-
         final String name;
+        final boolean strict; // true if module names are checked
+        boolean open;
         boolean automatic;
         boolean synthetic;
         final Map<String, Requires> requires = new HashMap<>();
-        final Set<String> uses = new HashSet<>();
+
         final Map<String, Exports> exports = new HashMap<>();
+        final Map<String, Opens> opens = new HashMap<>();
+        final Set<String> concealedPackages = new HashSet<>();
+
+        final Set<String> uses = new HashSet<>();
         final Map<String, Provides> provides = new HashMap<>();
-        Set<String> conceals = Collections.emptySet();
         Version version;
         String osName;
         String osArch;
@@ -1113,29 +1338,30 @@
         /**
          * Initializes a new builder with the given module name.
          *
-         * @param  name
-         *         The module name
-         *
-         * @throws IllegalArgumentException
-         *         If the module name is {@code null} or is not a legal Java
-         *         identifier
+         * @param strict
+         *        Indicates whether module names are checked or not
          */
-        public Builder(String name) {
-            this.name = requireModuleName(name);
+        Builder(String name, boolean strict) {
+            this.strict = strict;
+            this.name = (strict) ? requireModuleName(name) : name;
         }
 
-        /**
-         * Updates the builder so that it builds an automatic module.
-         *
-         * @return This builder
-         *
-         * @see ModuleDescriptor#isAutomatic()
-         */
-        /* package */ Builder automatic() {
-            this.automatic = true;
+        /* package */ Builder open(boolean open) {
+            this.open = open;
             return this;
         }
 
+        /* package */ Builder automatic(boolean automatic) {
+            this.automatic = automatic;
+            return this;
+        }
+
+        /* package */ boolean isOpen() { return open; }
+
+        /* package */ boolean isAutomatic() {
+            return automatic;
+        }
+
         /**
          * Adds a dependence on a module.
          *
@@ -1165,7 +1391,7 @@
          * Adds a dependence on a module with the given (and possibly empty)
          * set of modifiers.
          *
-         * @param  mods
+         * @param  ms
          *         The set of modifiers
          * @param  mn
          *         The module name
@@ -1179,14 +1405,10 @@
          * @throws IllegalStateException
          *         If the dependence on the module has already been declared
          */
-        public Builder requires(Set<Requires.Modifier> mods, String mn) {
-            if (name.equals(mn))
-                throw new IllegalArgumentException("Dependence on self");
-            if (requires.containsKey(mn))
-                throw new IllegalStateException("Dependence upon " + mn
-                                                + " already declared");
-            requires.put(mn, new Requires(mods, mn)); // checks mn
-            return this;
+        public Builder requires(Set<Requires.Modifier> ms, String mn) {
+            if (strict)
+                mn = requireModuleName(mn);
+            return requires(new Requires(ms, mn));
         }
 
         /**
@@ -1209,62 +1431,6 @@
         }
 
         /**
-         * Adds a dependence on a module with the given modifier.
-         *
-         * @param  mod
-         *         The modifier
-         * @param  mn
-         *         The module name
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If the module name is {@code null}, is not a legal Java
-         *         identifier, or is equal to the module name that this builder
-         *         was initialized to build
-         * @throws IllegalStateException
-         *         If the dependence on the module has already been declared
-         */
-        public Builder requires(Requires.Modifier mod, String mn) {
-            return requires(EnumSet.of(mod), mn);
-        }
-
-        /**
-         * Adds a service dependence.
-         *
-         * @param  st
-         *         The service type
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If the service type is {@code null} or is not a legal Java
-         *         identifier
-         * @throws IllegalStateException
-         *         If a dependency on the service type has already been declared
-         */
-        public Builder uses(String st) {
-            if (uses.contains(requireServiceTypeName(st)))
-                throw new IllegalStateException("Dependence upon service "
-                                                + st + " already declared");
-            uses.add(st);
-            return this;
-        }
-
-        /**
-         * Ensures that the given package name has not been declared as an
-         * exported or concealed package.
-         */
-        private void ensureNotExportedOrConcealed(String pn) {
-            if (exports.containsKey(pn))
-                throw new IllegalStateException("Export of package "
-                                                + pn + " already declared");
-            if (conceals.contains(pn))
-                throw new IllegalStateException("Concealed package "
-                                                + pn + " already declared");
-        }
-
-        /**
          * Adds an export.
          *
          * @param  e
@@ -1273,18 +1439,90 @@
          * @return This builder
          *
          * @throws IllegalStateException
-         *         If the package is already declared as an exported or
-         *         concealed package
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
          */
         public Builder exports(Exports e) {
-            String pn = e.source();
-            ensureNotExportedOrConcealed(pn);
-            exports.put(pn, e);
+            // can't be exported and concealed
+            String source = e.source();
+            if (concealedPackages.contains(source)) {
+                throw new IllegalStateException("Package " + source
+                                                 + " already declared");
+            }
+            if (exports.containsKey(source)) {
+                throw new IllegalStateException("Exported package " + source
+                                                 + " already declared");
+            }
+
+            exports.put(source, e);
             return this;
         }
 
         /**
-         * Adds an export to a set of target modules.
+         * Adds an export, with the given (and possibly empty) set of modifiers,
+         * to export a package to a set of target modules.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  pn
+         *         The package name
+         * @param  targets
+         *         The set of target modules names
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name or any of the target modules is {@code
+         *         null} or is not a legal Java identifier, or the set of
+         *         targets is empty
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
+         */
+        public Builder exports(Set<Exports.Modifier> ms,
+                               String pn,
+                               Set<String> targets)
+        {
+            Exports e = new Exports(ms, requirePackageName(pn), targets);
+
+            // check targets
+            targets = e.targets();
+            if (targets.isEmpty())
+                throw new IllegalArgumentException("Empty target set");
+            if (strict)
+                targets.stream().forEach(Checks::requireModuleName);
+
+            return exports(e);
+        }
+
+        /**
+         * Adds an unqualified export with the given (and possibly empty) set
+         * of modifiers.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  pn
+         *         The package name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
+         */
+        public Builder exports(Set<Exports.Modifier> ms, String pn) {
+            Exports e = new Exports(ms, requirePackageName(pn), Collections.emptySet());
+            return exports(e);
+        }
+
+        /**
+         * Adds an export to export a package to a set of target modules.
          *
          * @param  pn
          *         The package name
@@ -1298,38 +1536,16 @@
          *         null} or is not a legal Java identifier, or the set of
          *         targets is empty
          * @throws IllegalStateException
-         *         If the package is already declared as an exported or
-         *         concealed package
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
          */
         public Builder exports(String pn, Set<String> targets) {
-            ensureNotExportedOrConcealed(pn);
-            exports.put(pn, new Exports(pn, targets)); // checks pn and targets
-            return this;
+            return exports(Collections.emptySet(), pn, targets);
         }
 
         /**
-         * Adds an export to a target module.
-         *
-         * @param  pn
-         *         The package name
-         * @param  target
-         *         The target module name
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If the package name or target module is {@code null} or is
-         *         not a legal Java identifier
-         * @throws IllegalStateException
-         *         If the package is already declared as an exported or
-         *         concealed package
-         */
-        public Builder exports(String pn, String target) {
-            return exports(pn, Collections.singleton(target));
-        }
-
-        /**
-         * Adds an export.
+         * Adds an unqualified export.
          *
          * @param  pn
          *         The package name
@@ -1340,18 +1556,186 @@
          *         If the package name is {@code null} or is not a legal Java
          *         identifier
          * @throws IllegalStateException
-         *         If the package is already declared as an exported or
-         *         concealed package
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
          */
         public Builder exports(String pn) {
-            ensureNotExportedOrConcealed(pn);
-            exports.put(pn, new Exports(pn)); // checks pn
+            return exports(Collections.emptySet(), pn);
+        }
+
+        /**
+         * Adds an <em>opens</em> directive.
+         *
+         * @param  obj
+         *         The {@code Opens} object
+         *
+         * @return This builder
+         *
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(Opens obj) {
+            if (open) {
+                throw new IllegalStateException("open modules cannot declare"
+                                                + " open packages");
+            }
+
+            // can't be open and concealed
+            String source = obj.source();
+            if (concealedPackages.contains(source)) {
+                throw new IllegalStateException("Package " + source
+                                                + " already declared");
+            }
+            if (opens.containsKey(source)) {
+                throw new IllegalStateException("Open package " + source
+                                                + " already declared");
+            }
+
+            opens.put(source, obj);
             return this;
         }
 
+
+        /**
+         * Adds an <em>opens</em> directive, with the given (and possibly empty)
+         * set of modifiers, to open a package to a set of target modules.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  pn
+         *         The package name
+         * @param  targets
+         *         The set of target modules names
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name or any of the target modules is {@code
+         *         null} or is not a legal Java identifier, or the set of
+         *         targets is empty
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(Set<Opens.Modifier> ms,
+                             String pn,
+                             Set<String> targets)
+        {
+            Opens e = new Opens(ms, requirePackageName(pn), targets);
+
+            // check targets
+            targets = e.targets();
+            if (targets.isEmpty())
+                throw new IllegalArgumentException("Empty target set");
+            if (strict)
+                targets.stream().forEach(Checks::requireModuleName);
+
+            return opens(e);
+        }
+
+        /**
+         * Adds an <em>opens</em> directive to open a package with the given (and
+         * possibly empty) set of modifiers.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  pn
+         *         The package name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(Set<Opens.Modifier> ms, String pn) {
+            Opens e = new Opens(ms, requirePackageName(pn), Collections.emptySet());
+            return opens(e);
+        }
+
+        /**
+         * Adds an <em>opens</em> directive to open a package to a set of target
+         * modules.
+         *
+         * @param  pn
+         *         The package name
+         * @param  targets
+         *         The set of target modules names
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name or any of the target modules is {@code
+         *         null} or is not a legal Java identifier, or the set of
+         *         targets is empty
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(String pn, Set<String> targets) {
+            return opens(Collections.emptySet(), pn, targets);
+        }
+
+        /**
+         * Adds an <em>opens</em> directive to open a package.
+         *
+         * @param  pn
+         *         The package name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(String pn) {
+            return opens(Collections.emptySet(), pn);
+        }
+
+
         // Used by ModuleInfo, after a packageFinder is invoked
-        /* package */ Set<String> exportedPackages() {
-            return exports.keySet();
+        /* package */ Set<String> exportedAndOpenPackages() {
+            if (opens.isEmpty())
+                return exports.keySet();
+            Set<String> result = new HashSet<>();
+            result.addAll(exports.keySet());
+            result.addAll(opens.keySet());
+            return result;
+        }
+
+        /**
+         * Adds a service dependence.
+         *
+         * @param  service
+         *         The service type
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the service type is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If a dependency on the service type has already been declared
+         */
+        public Builder uses(String service) {
+            if (uses.contains(requireServiceTypeName(service)))
+                throw new IllegalStateException("Dependence upon service "
+                                                + service + " already declared");
+            uses.add(service);
+            return this;
         }
 
         /**
@@ -1376,38 +1760,47 @@
         }
 
         /**
-         * Provides service {@code st} with implementations {@code pcs}.
+         * Provides implementations of a service.
          *
-         * @param  st
+         * @param  service
          *         The service type
-         * @param  pcs
-         *         The set of provider class names
+         * @param  providers
+         *         The list of provider or provider factory class names
          *
          * @return This builder
          *
          * @throws IllegalArgumentException
          *         If the service type or any of the provider class names is
-         *         {@code null} or is not a legal Java identifier, or the set
+         *         {@code null} or is not a legal Java identifier, or the list
          *         of provider class names is empty
          * @throws IllegalStateException
          *         If the providers for the service type have already been
          *         declared
          */
-        public Builder provides(String st, Set<String> pcs) {
-            if (provides.containsKey(st))
+        public Builder provides(String service, List<String> providers) {
+            if (provides.containsKey(service))
                 throw new IllegalStateException("Providers of service "
-                                                + st + " already declared");
-            provides.put(st, new Provides(st, pcs)); // checks st and pcs
+                                                + service + " already declared by " + name);
+
+            Provides p = new Provides(requireServiceTypeName(service), providers);
+
+            // check providers after the set has been copied.
+            List<String> providerNames = p.providers();
+            if (providerNames.isEmpty())
+                throw new IllegalArgumentException("Empty providers set");
+            providerNames.forEach(Checks::requireServiceProviderName);
+
+            provides.put(service, p);
             return this;
         }
 
         /**
-         * Provides service {@code st} with implementation {@code pc}.
+         * Provides an implementation of a service.
          *
-         * @param  st
+         * @param  service
          *         The service type
-         * @param  pc
-         *         The provider class name
+         * @param  provider
+         *         The provider or provider factory class name
          *
          * @return This builder
          *
@@ -1418,15 +1811,17 @@
          *         If the providers for the service type have already been
          *         declared
          */
-        public Builder provides(String st, String pc) {
-            return provides(st, Collections.singleton(pc));
+        public Builder provides(String service, String provider) {
+            if (provider == null)
+                throw new IllegalArgumentException("'provider' is null");
+            return provides(service, List.of(provider));
         }
 
         /**
-         * Adds a set of (possible empty) concealed packages.
+         * Adds a (possible empty) set of packages to the module
          *
          * @param  pns
-         *         The set of package names of the concealed packages
+         *         The set of package names
          *
          * @return This builder
          *
@@ -1434,16 +1829,17 @@
          *         If any of the package names is {@code null} or is not a
          *         legal Java identifier
          * @throws IllegalStateException
-         *         If any of packages are already declared as a concealed or
-         *         exported package
+         *         If any of packages are already declared as packages in
+         *         the module. This includes packages that are already
+         *         declared as exported or open packages.
          */
-        public Builder conceals(Set<String> pns) {
-            pns.forEach(this::conceals);
+        public Builder contains(Set<String> pns) {
+            pns.forEach(this::contains);
             return this;
         }
 
         /**
-         * Adds a concealed package.
+         * Adds a package to the module.
          *
          * @param  pn
          *         The package name
@@ -1454,15 +1850,25 @@
          *         If the package name is {@code null}, or is not a legal Java
          *         identifier
          * @throws IllegalStateException
-         *         If the package is already declared as a concealed or exported
-         *         package
+         *         If the package is already declared as a package in the
+         *         module. This includes the package already declared as an
+         *         exported or open package.
          */
-        public Builder conceals(String pn) {
+        public Builder contains(String pn) {
             Checks.requirePackageName(pn);
-            ensureNotExportedOrConcealed(pn);
-            if (conceals.isEmpty())
-                conceals = new HashSet<>();
-            conceals.add(pn);
+            if (concealedPackages.contains(pn)) {
+                throw new IllegalStateException("Package " + pn
+                                                + " already declared");
+            }
+            if (exports.containsKey(pn)) {
+                throw new IllegalStateException("Exported package "
+                                                + pn + " already declared");
+            }
+            if (opens.containsKey(pn)) {
+                throw new IllegalStateException("Open package "
+                                                 + pn + " already declared");
+            }
+            concealedPackages.add(pn);
             return this;
         }
 
@@ -1473,13 +1879,8 @@
          *         The version
          *
          * @return This builder
-         *
-         * @throws IllegalStateException
-         *         If the module version is already set
          */
         public Builder version(Version v) {
-            if (version != null)
-                throw new IllegalStateException("module version already set");
             version = requireNonNull(v);
             return this;
         }
@@ -1494,16 +1895,11 @@
          *
          * @throws IllegalArgumentException
          *         If {@code v} is null or cannot be parsed as a version string
-         * @throws IllegalStateException
-         *         If the module version is already set
          *
          * @see Version#parse(String)
          */
         public Builder version(String v) {
-            if (version != null)
-                throw new IllegalStateException("module version already set");
-            version = Version.parse(v);
-            return this;
+            return version(Version.parse(v));
         }
 
         /**
@@ -1516,12 +1912,8 @@
          *
          * @throws IllegalArgumentException
          *         If {@code mainClass} is null or is not a legal Java identifier
-         * @throws IllegalStateException
-         *         If the module main class is already set
          */
         public Builder mainClass(String mc) {
-            if (mainClass != null)
-                throw new IllegalStateException("main class already set");
             mainClass = requireJavaIdentifier("main class name", mc);
             return this;
         }
@@ -1536,12 +1928,8 @@
          *
          * @throws IllegalArgumentException
          *         If {@code name} is null or the empty String
-         * @throws IllegalStateException
-         *         If the operating system name is already set
          */
         public Builder osName(String name) {
-            if (osName != null)
-                throw new IllegalStateException("OS name already set");
             if (name == null || name.isEmpty())
                 throw new IllegalArgumentException("OS name is null or empty");
             osName = name;
@@ -1558,12 +1946,8 @@
          *
          * @throws IllegalArgumentException
          *         If {@code name} is null or the empty String
-         * @throws IllegalStateException
-         *         If the operating system architecture is already set
          */
         public Builder osArch(String arch) {
-            if (osArch != null)
-                throw new IllegalStateException("OS arch already set");
             if (arch == null || arch.isEmpty())
                 throw new IllegalArgumentException("OS arch is null or empty");
             osArch = arch;
@@ -1580,12 +1964,8 @@
          *
          * @throws IllegalArgumentException
          *         If {@code name} is null or the empty String
-         * @throws IllegalStateException
-         *         If the operating system version is already set
          */
         public Builder osVersion(String version) {
-            if (osVersion != null)
-                throw new IllegalStateException("OS version already set");
             if (version == null || version.isEmpty())
                 throw new IllegalArgumentException("OS version is null or empty");
             osVersion = version;
@@ -1597,7 +1977,6 @@
             return this;
         }
 
-
         /* package */ Builder synthetic(boolean v) {
             this.synthetic = v;
             return this;
@@ -1609,16 +1988,24 @@
          * @return The module descriptor
          */
         public ModuleDescriptor build() {
-            assert name != null;
+            Set<Requires> requires = new HashSet<>(this.requires.values());
+
+            Set<String> packages = new HashSet<>(exportedAndOpenPackages());
+            packages.addAll(concealedPackages);
 
-            Set<String> packages = new HashSet<>(conceals);
-            packages.addAll(exportedPackages());
+            Set<Exports> exports = new HashSet<>(this.exports.values());
+            Set<Opens> opens = new HashSet<>(this.opens.values());
+
+            Set<Provides> provides = new HashSet<>(this.provides.values());
+
             return new ModuleDescriptor(name,
+                                        open,
                                         automatic,
                                         synthetic,
                                         requires,
+                                        exports,
+                                        opens,
                                         uses,
-                                        exports,
                                         provides,
                                         version,
                                         mainClass,
@@ -1631,7 +2018,6 @@
 
     }
 
-
     /**
      * Compares this module descriptor to another.
      *
@@ -1689,11 +2075,13 @@
             return false;
         ModuleDescriptor that = (ModuleDescriptor)ob;
         return (name.equals(that.name)
+                && open == that.open
                 && automatic == that.automatic
                 && synthetic == that.synthetic
                 && requires.equals(that.requires)
+                && exports.equals(that.exports)
+                && opens.equals(that.opens)
                 && uses.equals(that.uses)
-                && exports.equals(that.exports)
                 && provides.equals(that.provides)
                 && Objects.equals(version, that.version)
                 && Objects.equals(mainClass, that.mainClass)
@@ -1720,11 +2108,13 @@
         int hc = hash;
         if (hc == 0) {
             hc = name.hashCode();
+            hc = hc * 43 + Boolean.hashCode(open);
             hc = hc * 43 + Boolean.hashCode(automatic);
             hc = hc * 43 + Boolean.hashCode(synthetic);
             hc = hc * 43 + requires.hashCode();
+            hc = hc * 43 + exports.hashCode();
+            hc = hc * 43 + opens.hashCode();
             hc = hc * 43 + uses.hashCode();
-            hc = hc * 43 + exports.hashCode();
             hc = hc * 43 + provides.hashCode();
             hc = hc * 43 + Objects.hashCode(version);
             hc = hc * 43 + Objects.hashCode(mainClass);
@@ -1748,36 +2138,101 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("Module { name: ").append(toNameAndVersion());
+
+        if (isOpen())
+            sb.append("open ");
+        sb.append("module { name: ").append(toNameAndVersion());
         if (!requires.isEmpty())
             sb.append(", ").append(requires);
         if (!uses.isEmpty())
             sb.append(", ").append(uses);
         if (!exports.isEmpty())
             sb.append(", exports: ").append(exports);
+        if (!opens.isEmpty())
+            sb.append(", opens: ").append(opens);
         if (!provides.isEmpty()) {
-            sb.append(", provides: [");
-            for (Map.Entry<String, Provides> entry : provides.entrySet()) {
-                sb.append(entry.getKey())
-                   .append(" with ")
-                   .append(entry.getValue());
-            }
-            sb.append("]");
+            sb.append(", provides: ").append(provides);
         }
         sb.append(" }");
         return sb.toString();
     }
 
+
+    /**
+     * Instantiates a builder to build a module descriptor.
+     *
+     * @param  name
+     *         The module name
+     *
+     * @return A new builder
+     *
+     * @throws IllegalArgumentException
+     *         If the module name is {@code null} or is not a legal Java
+     *         identifier
+     */
+    public static Builder module(String name) {
+        return new Builder(name, true);
+    }
+
+    /**
+     * Instantiates a builder to build a module descriptor for an open module.
+     * An open module does not declare any open packages but the resulting
+     * module is treated as if all packages are open.
+     *
+     * <p> As an example, the following creates a module descriptor for an open
+     * name "{@code m}" containing two packages, one of which is exported. </p>
+     * <pre>{@code
+     *     ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
+     *         .requires("java.base")
+     *         .exports("p")
+     *         .contains("q")
+     *         .build();
+     * }</pre>
+     *
+     * @param  name
+     *         The module name
+     *
+     * @return A new builder that builds an open module
+     *
+     * @throws IllegalArgumentException
+     *         If the module name is {@code null} or is not a legal Java
+     *         identifier
+     */
+    public static Builder openModule(String name) {
+        return new Builder(name, true).open(true);
+    }
+
+    /**
+     * Instantiates a builder to build a module descriptor for an automatic
+     * module. Automatic modules receive special treatment during resolution
+     * (see {@link Configuration}) so that they read all other modules. When
+     * Instantiated in the Java virtual machine as a {@link java.lang.reflect.Module}
+     * then the Module reads every unnamed module in the Java virtual machine.
+     *
+     * @param  name
+     *         The module name
+     *
+     * @return A new builder that builds an automatic module
+     *
+     * @throws IllegalArgumentException
+     *         If the module name is {@code null} or is not a legal Java
+     *         identifier
+     *
+     * @see ModuleFinder#of(Path[])
+     */
+    public static Builder automaticModule(String name) {
+        return new Builder(name, true).automatic(true);
+    }
+
+
     /**
      * Reads the binary form of a module declaration from an input stream
      * as a module descriptor.
      *
      * <p> If the descriptor encoded in the input stream does not indicate a
-     * set of concealed packages then the {@code packageFinder} will be
-     * invoked.  The packages it returns, except for those indicated as
-     * exported in the encoded descriptor, will be considered to be concealed.
-     * If the {@code packageFinder} throws an {@link UncheckedIOException} then
-     * {@link IOException} cause will be re-thrown. </p>
+     * set of packages in the module then the {@code packageFinder} will be
+     * invoked. If the {@code packageFinder} throws an {@link UncheckedIOException}
+     * then {@link IOException} cause will be re-thrown. </p>
      *
      * <p> If there are bytes following the module descriptor then it is
      * implementation specific as to whether those bytes are read, ignored,
@@ -1789,12 +2244,12 @@
      *
      * @apiNote The {@code packageFinder} parameter is for use when reading
      * module descriptors from legacy module-artifact formats that do not
-     * record the set of concealed packages in the descriptor itself.
+     * record the set of packages in the descriptor itself.
      *
      * @param  in
      *         The input stream
      * @param  packageFinder
-     *         A supplier that can produce a set of package names
+     *         A supplier that can produce the set of packages
      *
      * @return The module descriptor
      *
@@ -1834,10 +2289,7 @@
      * as a module descriptor.
      *
      * <p> If the descriptor encoded in the byte buffer does not indicate a
-     * set of concealed packages then the {@code packageFinder} will be
-     * invoked.  The packages it returns, except for those indicated as
-     * exported in the encoded descriptor, will be considered to be
-     * concealed. </p>
+     * set of packages then the {@code packageFinder} will be invoked. </p>
      *
      * <p> The module descriptor is read from the buffer stating at index
      * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position()
@@ -1853,12 +2305,12 @@
      *
      * @apiNote The {@code packageFinder} parameter is for use when reading
      * module descriptors from legacy module-artifact formats that do not
-     * record the set of concealed packages in the descriptor itself.
+     * record the set of packages in the descriptor itself.
      *
      * @param  bb
      *         The byte buffer
      * @param  packageFinder
-     *         A supplier that can produce a set of package names
+     *         A supplier that can produce the set of packages
      *
      * @return The module descriptor
      *
@@ -1908,6 +2360,15 @@
         }
     }
 
+    /**
+     * Returns a string containing the given set of modifiers and label.
+     */
+    private static <M> String toString(Set<M> mods, String what) {
+        return (Stream.concat(mods.stream().map(e -> e.toString().toLowerCase()),
+                              Stream.of(what)))
+                .collect(Collectors.joining(" "));
+    }
+
     static {
         /**
          * Setup the shared secret to allow code in other packages access
@@ -1915,25 +2376,48 @@
          */
         jdk.internal.misc.SharedSecrets
             .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
+                @Override
+                public Builder newModuleBuilder(String mn, boolean strict) {
+                    return new Builder(mn, strict);
+                }
+
+                @Override
+                public Builder newOpenModuleBuilder(String mn, boolean strict) {
+                    return new Builder(mn, strict).open(true);
+                }
 
                 @Override
                 public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
-                    return new Requires(ms, mn, false);
+                    return new Requires(ms, mn, true);
+                }
+
+                @Override
+                public Exports newExports(Set<Exports.Modifier> ms, String source) {
+                    return new Exports(ms, source, Collections.emptySet(), true);
                 }
 
                 @Override
-                public Exports newExports(String source, Set<String> targets) {
-                    return new Exports(source, targets, false);
+                public Exports newExports(Set<Exports.Modifier> ms,
+                                          String source,
+                                          Set<String> targets) {
+                    return new Exports(ms, source, targets, true);
                 }
 
                 @Override
-                public Exports newExports(String source) {
-                    return new Exports(source, false);
+                public Opens newOpens(Set<Opens.Modifier> ms,
+                                      String source,
+                                      Set<String> targets) {
+                    return new Opens(ms, source, targets, true);
                 }
 
                 @Override
-                public Provides newProvides(String service, Set<String> providers) {
-                    return new Provides(service, providers, false);
+                public Opens newOpens(Set<Opens.Modifier> ms, String source) {
+                    return new Opens(ms, source, Collections.emptySet(), true);
+                }
+
+                @Override
+                public Provides newProvides(String service, List<String> providers) {
+                    return new Provides(service, providers, true);
                 }
 
                 @Override
@@ -1949,25 +2433,30 @@
 
                 @Override
                 public ModuleDescriptor newModuleDescriptor(String name,
+                                                            boolean open,
                                                             boolean automatic,
                                                             boolean synthetic,
                                                             Set<Requires> requires,
+                                                            Set<Exports> exports,
+                                                            Set<Opens> opens,
                                                             Set<String> uses,
-                                                            Set<Exports> exports,
-                                                            Map<String, Provides> provides,
+                                                            Set<Provides> provides,
                                                             Version version,
                                                             String mainClass,
                                                             String osName,
                                                             String osArch,
                                                             String osVersion,
                                                             Set<String> packages,
-                                                            ModuleHashes hashes) {
+                                                            ModuleHashes hashes,
+                                                            int hashCode) {
                     return new ModuleDescriptor(name,
+                                                open,
                                                 automatic,
                                                 synthetic,
                                                 requires,
+                                                exports,
+                                                opens,
                                                 uses,
-                                                exports,
                                                 provides,
                                                 version,
                                                 mainClass,
@@ -1975,7 +2464,14 @@
                                                 osArch,
                                                 osVersion,
                                                 packages,
-                                                hashes);
+                                                hashes,
+                                                hashCode,
+                                                false);
+                }
+
+                @Override
+                public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
+                    return descriptor.hashes();
                 }
 
                 @Override
@@ -1995,11 +2491,6 @@
                 }
 
                 @Override
-                public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
-                    return descriptor.hashes();
-                }
-
-                @Override
                 public ModuleFinder newModulePath(Runtime.Version version,
                                                   boolean isLinkPhase,
                                                   Path... entries) {
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Wed Jul 05 22:32:06 2017 +0200
@@ -233,10 +233,11 @@
      *         ModuleDescriptor.Version} and ignored if it cannot be parsed as
      *         a {@code Version}. </p></li>
      *
-     *         <li><p> For the module name, then all non-alphanumeric
-     *         characters ({@code [^A-Za-z0-9])} are replaced with a dot
-     *         ({@code "."}), all repeating dots are replaced with one dot,
-     *         and all leading and trailing dots are removed. </p></li>
+     *         <li><p> For the module name, then any trailing digits and dots
+     *         are removed, all non-alphanumeric characters ({@code [^A-Za-z0-9]})
+     *         are replaced with a dot ({@code "."}), all repeating dots are
+     *         replaced with one dot, and all leading and trailing dots are
+     *         removed. </p></li>
      *
      *         <li><p> As an example, a JAR file named {@code foo-bar.jar} will
      *         derive a module name {@code foo.bar} and no version. A JAR file
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,13 +31,17 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleDescriptor.Builder;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.nio.ByteBuffer;
 import java.nio.BufferUnderflowException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Supplier;
@@ -56,15 +60,12 @@
 
 final class ModuleInfo {
 
-    // supplies the set of packages when ConcealedPackages not present
+    // supplies the set of packages when ModulePackages attribute not present
     private final Supplier<Set<String>> packageFinder;
 
-    // indicates if the Hashes attribute should be parsed
+    // indicates if the ModuleHashes attribute should be parsed
     private final boolean parseHashes;
 
-    // the builder, created when parsing
-    private ModuleDescriptor.Builder builder;
-
     private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
         packageFinder = pf;
         parseHashes = ph;
@@ -86,9 +87,8 @@
     {
         try {
             return new ModuleInfo(pf).doRead(new DataInputStream(in));
-        } catch (IllegalArgumentException iae) {
-            // IllegalArgumentException means a malformed class
-            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
         } catch (EOFException x) {
             throw truncatedModuleDescriptor();
         }
@@ -105,9 +105,8 @@
     {
         try {
             return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException iae) {
-            // IllegalArgumentException means a malformed class
-            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
         } catch (EOFException x) {
             throw truncatedModuleDescriptor();
         } catch (IOException ioe) {
@@ -117,7 +116,7 @@
 
     /**
      * Reads a {@code module-info.class} from the given byte buffer
-     * but ignore the {@code Hashes} attribute.
+     * but ignore the {@code ModuleHashes} attribute.
      *
      * @throws InvalidModuleDescriptorException
      * @throws UncheckedIOException
@@ -127,8 +126,8 @@
     {
         try {
             return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException iae) {
-            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
         } catch (EOFException x) {
             throw truncatedModuleDescriptor();
         } catch (IOException ioe) {
@@ -164,12 +163,8 @@
             throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
 
         int this_class = in.readUnsignedShort();
-        String mn = cpool.getClassName(this_class);
-        int suffix = mn.indexOf("/module-info");
-        if (suffix < 1)
-            throw invalidModuleDescriptor("this_class not of form name/module-info");
-        mn = mn.substring(0, suffix).replace('/', '.');
-        builder = new ModuleDescriptor.Builder(mn);
+        if (this_class != 0)
+            throw invalidModuleDescriptor("this_class must be 0");
 
         int super_class = in.readUnsignedShort();
         if (super_class > 0)
@@ -192,6 +187,13 @@
         // the names of the attributes found in the class file
         Set<String> attributes = new HashSet<>();
 
+        Builder builder = null;
+        Set<String> packages = null;
+        String version = null;
+        String mainClass = null;
+        String[] osValues = null;
+        ModuleHashes hashes = null;
+
         for (int i = 0; i < attributes_count ; i++) {
             int name_index = in.readUnsignedShort();
             String attribute_name = cpool.getUtf8(name_index);
@@ -206,28 +208,28 @@
             switch (attribute_name) {
 
                 case MODULE :
-                    readModuleAttribute(mn, in, cpool);
+                    builder = readModuleAttribute(in, cpool);
                     break;
 
-                case CONCEALED_PACKAGES :
-                    readConcealedPackagesAttribute(in, cpool);
+                case MODULE_PACKAGES :
+                    packages = readModulePackagesAttribute(in, cpool);
                     break;
 
-                case VERSION :
-                    readVersionAttribute(in, cpool);
+                case MODULE_VERSION :
+                    version = readModuleVersionAttribute(in, cpool);
                     break;
 
-                case MAIN_CLASS :
-                    readMainClassAttribute(in, cpool);
+                case MODULE_MAIN_CLASS :
+                    mainClass = readModuleMainClassAttribute(in, cpool);
                     break;
 
-                case TARGET_PLATFORM :
-                    readTargetPlatformAttribute(in, cpool);
+                case MODULE_TARGET :
+                    osValues = readModuleTargetAttribute(in, cpool);
                     break;
 
-                case HASHES :
+                case MODULE_HASHES :
                     if (parseHashes) {
-                        readHashesAttribute(in, cpool);
+                        hashes = readModuleHashesAttribute(in, cpool);
                     } else {
                         in.skipBytes(length);
                     }
@@ -245,53 +247,91 @@
         }
 
         // the Module attribute is required
-        if (!attributes.contains(MODULE)) {
+        if (builder == null) {
             throw invalidModuleDescriptor(MODULE + " attribute not found");
         }
 
-        // If the ConcealedPackages attribute is not present then the
-        // packageFinder is used to to find any non-exported packages.
-        if (!attributes.contains(CONCEALED_PACKAGES) && packageFinder != null) {
-            Set<String> pkgs;
+        // If the ModulePackages attribute is not present then the packageFinder
+        // is used to find the set of packages
+        boolean usedPackageFinder = false;
+        if (packages == null && packageFinder != null) {
             try {
-                pkgs = new HashSet<>(packageFinder.get());
+                packages = new HashSet<>(packageFinder.get());
             } catch (UncheckedIOException x) {
                 throw x.getCause();
             }
-            pkgs.removeAll(builder.exportedPackages());
-            builder.conceals(pkgs);
+            usedPackageFinder = true;
+        }
+        if (packages != null) {
+            for (String pn : builder.exportedAndOpenPackages()) {
+                if (!packages.contains(pn)) {
+                    String tail;
+                    if (usedPackageFinder) {
+                        tail = " not found by package finder";
+                    } else {
+                        tail = " missing from ModulePackages attribute";
+                    }
+                    throw invalidModuleDescriptor("Package " + pn + tail);
+                }
+                packages.remove(pn);
+            }
+            builder.contains(packages);
         }
 
-        // Was the Synthetic attribute present?
-        if (attributes.contains(SYNTHETIC))
-            builder.synthetic(true);
+        if (version != null)
+            builder.version(version);
+        if (mainClass != null)
+            builder.mainClass(mainClass);
+        if (osValues != null) {
+            if (osValues[0] != null) builder.osName(osValues[0]);
+            if (osValues[1] != null) builder.osArch(osValues[1]);
+            if (osValues[2] != null) builder.osVersion(osValues[2]);
+        }
+        if (hashes != null)
+            builder.hashes(hashes);
 
         return builder.build();
     }
 
     /**
-     * Reads the Module attribute.
+     * Reads the Module attribute, returning the ModuleDescriptor.Builder to
+     * build the corresponding ModuleDescriptor.
      */
-    private void readModuleAttribute(String mn, DataInput in, ConstantPool cpool)
+    private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
+        // module_name
+        int module_name_index = in.readUnsignedShort();
+        String mn = cpool.getUtf8AsBinaryName(module_name_index);
+
+        Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
+
+        int module_flags = in.readUnsignedShort();
+        boolean open = ((module_flags & ACC_OPEN) != 0);
+        if (open)
+            builder.open(true);
+        if ((module_flags & ACC_SYNTHETIC) != 0)
+            builder.synthetic(true);
+
         int requires_count = in.readUnsignedShort();
         boolean requiresJavaBase = false;
         for (int i=0; i<requires_count; i++) {
             int index = in.readUnsignedShort();
             int flags = in.readUnsignedShort();
-            String dn = cpool.getUtf8(index);
-            Set<Modifier> mods;
+            String dn = cpool.getUtf8AsBinaryName(index);
+            Set<Requires.Modifier> mods;
             if (flags == 0) {
                 mods = Collections.emptySet();
             } else {
                 mods = new HashSet<>();
-                if ((flags & ACC_PUBLIC) != 0)
-                    mods.add(Modifier.PUBLIC);
+                if ((flags & ACC_TRANSITIVE) != 0)
+                    mods.add(Requires.Modifier.TRANSITIVE);
+                if ((flags & ACC_STATIC_PHASE) != 0)
+                    mods.add(Requires.Modifier.STATIC);
                 if ((flags & ACC_SYNTHETIC) != 0)
-                    mods.add(Modifier.SYNTHETIC);
+                    mods.add(Requires.Modifier.SYNTHETIC);
                 if ((flags & ACC_MANDATED) != 0)
-                    mods.add(Modifier.MANDATED);
+                    mods.add(Requires.Modifier.MANDATED);
             }
             builder.requires(mods, dn);
             if (dn.equals("java.base"))
@@ -311,17 +351,66 @@
         if (exports_count > 0) {
             for (int i=0; i<exports_count; i++) {
                 int index = in.readUnsignedShort();
-                String pkg = cpool.getUtf8(index).replace('/', '.');
+                String pkg = cpool.getUtf8AsBinaryName(index);
+
+                Set<Exports.Modifier> mods;
+                int flags = in.readUnsignedShort();
+                if (flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Exports.Modifier.SYNTHETIC);
+                    if ((flags & ACC_MANDATED) != 0)
+                        mods.add(Exports.Modifier.MANDATED);
+                }
+
                 int exports_to_count = in.readUnsignedShort();
                 if (exports_to_count > 0) {
                     Set<String> targets = new HashSet<>(exports_to_count);
                     for (int j=0; j<exports_to_count; j++) {
                         int exports_to_index = in.readUnsignedShort();
-                        targets.add(cpool.getUtf8(exports_to_index));
+                        targets.add(cpool.getUtf8AsBinaryName(exports_to_index));
                     }
-                    builder.exports(pkg, targets);
+                    builder.exports(mods, pkg, targets);
                 } else {
-                    builder.exports(pkg);
+                    builder.exports(mods, pkg);
+                }
+            }
+        }
+
+        int opens_count = in.readUnsignedShort();
+        if (opens_count > 0) {
+            if (open) {
+                throw invalidModuleDescriptor("The opens table for an open"
+                                              + " module must be 0 length");
+            }
+            for (int i=0; i<opens_count; i++) {
+                int index = in.readUnsignedShort();
+                String pkg = cpool.getUtf8AsBinaryName(index);
+
+                Set<Opens.Modifier> mods;
+                int flags = in.readUnsignedShort();
+                if (flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Opens.Modifier.SYNTHETIC);
+                    if ((flags & ACC_MANDATED) != 0)
+                        mods.add(Opens.Modifier.MANDATED);
+                }
+
+                int open_to_count = in.readUnsignedShort();
+                if (open_to_count > 0) {
+                    Set<String> targets = new HashSet<>(open_to_count);
+                    for (int j=0; j<open_to_count; j++) {
+                        int opens_to_index = in.readUnsignedShort();
+                        targets.add(cpool.getUtf8AsBinaryName(opens_to_index));
+                    }
+                    builder.opens(mods, pkg, targets);
+                } else {
+                    builder.opens(mods, pkg);
                 }
             }
         }
@@ -330,111 +419,114 @@
         if (uses_count > 0) {
             for (int i=0; i<uses_count; i++) {
                 int index = in.readUnsignedShort();
-                String sn = cpool.getClassName(index).replace('/', '.');
+                String sn = cpool.getClassNameAsBinaryName(index);
                 builder.uses(sn);
             }
         }
 
         int provides_count = in.readUnsignedShort();
         if (provides_count > 0) {
-            Map<String, Set<String>> pm = new HashMap<>();
             for (int i=0; i<provides_count; i++) {
                 int index = in.readUnsignedShort();
-                int with_index = in.readUnsignedShort();
-                String sn = cpool.getClassName(index).replace('/', '.');
-                String cn = cpool.getClassName(with_index).replace('/', '.');
-                // computeIfAbsent
-                Set<String> providers = pm.get(sn);
-                if (providers == null) {
-                    providers = new LinkedHashSet<>(); // preserve order
-                    pm.put(sn, providers);
+                String sn = cpool.getClassNameAsBinaryName(index);
+                int with_count = in.readUnsignedShort();
+                List<String> providers = new ArrayList<>(with_count);
+                for (int j=0; j<with_count; j++) {
+                    index = in.readUnsignedShort();
+                    String pn = cpool.getClassNameAsBinaryName(index);
+                    providers.add(pn);
                 }
-                providers.add(cn);
-            }
-            for (Map.Entry<String, Set<String>> e : pm.entrySet()) {
-                builder.provides(e.getKey(), e.getValue());
+                builder.provides(sn, providers);
             }
         }
+
+        return builder;
     }
 
     /**
-     * Reads the ConcealedPackages attribute
+     * Reads the ModulePackages attribute
      */
-    private void readConcealedPackagesAttribute(DataInput in, ConstantPool cpool)
+    private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
         int package_count = in.readUnsignedShort();
+        Set<String> packages = new HashSet<>(package_count);
         for (int i=0; i<package_count; i++) {
             int index = in.readUnsignedShort();
-            String pn = cpool.getUtf8(index).replace('/', '.');
-            builder.conceals(pn);
+            String pn = cpool.getUtf8AsBinaryName(index);
+            packages.add(pn);
         }
+        return packages;
     }
 
     /**
-     * Reads the Version attribute
+     * Reads the ModuleVersion attribute
      */
-    private void readVersionAttribute(DataInput in, ConstantPool cpool)
+    private String readModuleVersionAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
         int index = in.readUnsignedShort();
-        builder.version(cpool.getUtf8(index));
+        return cpool.getUtf8(index);
     }
 
     /**
-     * Reads the MainClass attribute
+     * Reads the ModuleMainClass attribute
      */
-    private void readMainClassAttribute(DataInput in, ConstantPool cpool)
+    private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
         int index = in.readUnsignedShort();
-        builder.mainClass(cpool.getClassName(index).replace('/', '.'));
+        return cpool.getClassNameAsBinaryName(index);
     }
 
     /**
-     * Reads the TargetPlatform attribute
+     * Reads the ModuleTarget attribute
      */
-    private void readTargetPlatformAttribute(DataInput in, ConstantPool cpool)
+    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
+        String[] values = new String[3];
+
         int name_index = in.readUnsignedShort();
         if (name_index != 0)
-            builder.osName(cpool.getUtf8(name_index));
+            values[0] = cpool.getUtf8(name_index);
 
         int arch_index = in.readUnsignedShort();
         if (arch_index != 0)
-            builder.osArch(cpool.getUtf8(arch_index));
+            values[1] = cpool.getUtf8(arch_index);
 
         int version_index = in.readUnsignedShort();
         if (version_index != 0)
-            builder.osVersion(cpool.getUtf8(version_index));
+            values[2] = cpool.getUtf8(version_index);
+
+        return values;
     }
 
 
     /**
-     * Reads the Hashes attribute
-     *
-     * @apiNote For now the hash is stored in base64 as a UTF-8 string, this
-     * should be changed to be an array of u1.
+     * Reads the ModuleHashes attribute
      */
-    private void readHashesAttribute(DataInput in, ConstantPool cpool)
+    private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
-        int index = in.readUnsignedShort();
-        String algorithm = cpool.getUtf8(index);
+        int algorithm_index = in.readUnsignedShort();
+        String algorithm = cpool.getUtf8(algorithm_index);
 
         int hash_count = in.readUnsignedShort();
-
-        Map<String, String> map = new HashMap<>(hash_count);
+        Map<String, byte[]> map = new HashMap<>(hash_count);
         for (int i=0; i<hash_count; i++) {
-            index = in.readUnsignedShort();
-            String dn = cpool.getUtf8(index);
-            index = in.readUnsignedShort();
-            String hash = cpool.getUtf8(index);
-            map.put(dn, hash);
+            int module_name_index = in.readUnsignedShort();
+            String mn = cpool.getUtf8AsBinaryName(module_name_index);
+            int hash_length = in.readUnsignedShort();
+            if (hash_length == 0) {
+                throw invalidModuleDescriptor("hash_length == 0");
+            }
+            byte[] hash = new byte[hash_length];
+            in.readFully(hash);
+            map.put(mn, hash);
         }
 
-        builder.hashes(new ModuleHashes(algorithm, map));
+        return new ModuleHashes(algorithm, map);
     }
 
 
@@ -447,11 +539,11 @@
         if (name.equals(MODULE) ||
                 name.equals(SOURCE_FILE) ||
                 name.equals(SDE) ||
-                name.equals(CONCEALED_PACKAGES) ||
-                name.equals(VERSION) ||
-                name.equals(MAIN_CLASS) ||
-                name.equals(TARGET_PLATFORM) ||
-                name.equals(HASHES))
+                name.equals(MODULE_PACKAGES) ||
+                name.equals(MODULE_VERSION) ||
+                name.equals(MODULE_MAIN_CLASS) ||
+                name.equals(MODULE_TARGET) ||
+                name.equals(MODULE_HASHES))
             return true;
 
         return false;
@@ -461,8 +553,8 @@
      * Return true if the given attribute name is the name of a pre-defined
      * attribute that is not allowed in the class file.
      *
-     * Except for Module, InnerClasses, Synthetic, SourceFile, SourceDebugExtension,
-     * and Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
+     * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
+     * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
      */
     private static boolean isAttributeDisallowed(String name) {
         Set<String> notAllowed = predefinedNotAllowed;
@@ -477,12 +569,11 @@
                     "LineNumberTable",
                     "LocalVariableTable",
                     "LocalVariableTypeTable",
-                    "RuntimeVisibleAnnotations",
-                    "RuntimeInvisibleAnnotations",
                     "RuntimeVisibleParameterAnnotations",
                     "RuntimeInvisibleParameterAnnotations",
                     "RuntimeVisibleTypeAnnotations",
                     "RuntimeInvisibleTypeAnnotations",
+                    "Synthetic",
                     "AnnotationDefault",
                     "BootstrapMethods",
                     "MethodParameters");
@@ -495,7 +586,6 @@
     private static volatile Set<String> predefinedNotAllowed;
 
 
-
     /**
      * The constant pool in a class file.
      */
@@ -628,6 +718,11 @@
             return getUtf8(((IndexEntry) e).index);
         }
 
+        String getClassNameAsBinaryName(int index) {
+            String value = getClassName(index);
+            return value.replace('/', '.');  // internal form -> binary name
+        }
+
         String getUtf8(int index) {
             checkIndex(index);
             Entry e = pool[index];
@@ -638,6 +733,11 @@
             return (String) (((ValueEntry) e).value);
         }
 
+        String getUtf8AsBinaryName(int index) {
+            String value = getUtf8(index);
+            return value.replace('/', '.');  // internal -> binary name
+        }
+
         void checkIndex(int index) {
             if (index < 1 || index >= pool.length)
                 throw invalidModuleDescriptor("Index into constant pool out of range");
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Wed Jul 05 22:32:06 2017 +0200
@@ -40,9 +40,10 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -54,7 +55,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 import jdk.internal.jmod.JmodFile;
@@ -399,8 +399,8 @@
      *
      * 1. The module name (and optionally the version) is derived from the file
      *    name of the JAR file
-     * 2. The packages of all .class files in the JAR file are exported
-     * 3. It has no module-private/concealed packages
+     * 2. All packages are exported and open
+     * 3. It has no non-exported/non-open packages
      * 4. The contents of any META-INF/services configuration files are mapped
      *    to "provides" declarations
      * 5. The Main-Class attribute in the main attributes of the JAR manifest
@@ -440,8 +440,7 @@
 
         // Builder throws IAE if module name is empty or invalid
         ModuleDescriptor.Builder builder
-            = new ModuleDescriptor.Builder(mn)
-                .automatic()
+            = ModuleDescriptor.automaticModule(mn)
                 .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
         if (vs != null)
             builder.version(vs);
@@ -455,13 +454,12 @@
 
         Set<String> resources = map.get(Boolean.FALSE);
         Set<String> configFiles = map.get(Boolean.TRUE);
-
-        // all packages are exported
+        // all packages are exported and open
         resources.stream()
                 .map(this::toPackageName)
                 .flatMap(Optional::stream)
                 .distinct()
-                .forEach(builder::exports);
+                .forEach(pn -> builder.exports(pn).opens(pn));
 
         // map names of service configuration files to service names
         Set<String> serviceNames = configFiles.stream()
@@ -472,7 +470,7 @@
         // parse each service configuration file
         for (String sn : serviceNames) {
             JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
-            Set<String> providerClasses = new LinkedHashSet<>();
+            List<String> providerClasses = new ArrayList<>();
             try (InputStream in = jf.getInputStream(entry)) {
                 BufferedReader reader
                     = new BufferedReader(new InputStreamReader(in, "UTF-8"));
@@ -493,7 +491,7 @@
             Attributes attrs = man.getMainAttributes();
             String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
             if (mainClass != null)
-                builder.mainClass(mainClass);
+                builder.mainClass(mainClass.replace("/", "."));
         }
 
         return builder.build();
@@ -504,6 +502,7 @@
      */
     private static class Patterns {
         static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
+        static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
         static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
         static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
         static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
@@ -514,6 +513,9 @@
      * Clean up candidate module name derived from a JAR file name.
      */
     private static String cleanModuleName(String mn) {
+        // drop trailing version from name
+        mn = Patterns.TRAILING_VERSION.matcher(mn).replaceAll("");
+
         // replace non-alphanumeric
         mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll(".");
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Wed Jul 05 22:32:06 2017 +0200
@@ -60,8 +60,8 @@
     // the function that computes the hash of this module reference
     private final HashSupplier hasher;
 
-    // cached hash string to avoid needing to compute it many times
-    private String cachedHash;
+    // cached hash to avoid needing to compute it many times
+    private byte[] cachedHash;
 
 
     /**
@@ -183,13 +183,13 @@
     }
 
     /**
-     * Computes the hash of this module, returning it as a hex string.
-     * Returns {@code null} if the hash cannot be computed.
+     * Computes the hash of this module. Returns {@code null} if the hash
+     * cannot be computed.
      *
      * @throws java.io.UncheckedIOException if an I/O error occurs
      */
-    String computeHash(String algorithm) {
-        String result = cachedHash;
+    byte[] computeHash(String algorithm) {
+        byte[] result = cachedHash;
         if (result != null)
             return result;
         if (hasher == null)
@@ -211,8 +211,11 @@
     public int hashCode() {
         int hc = hash;
         if (hc == 0) {
-            hc = Objects.hash(descriptor, location, readerSupplier, hasher,
-                    Boolean.valueOf(patched));
+            hc = descriptor.hashCode();
+            hc = 43 * hc + readerSupplier.hashCode();
+            hc = 43 * hc + Objects.hashCode(location);
+            hc = 43 * hc + Objects.hashCode(hasher);
+            hc = 43 * hc + Boolean.hashCode(patched);
             if (hc == 0)
                 hc = -1;
             hash = hc;
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Wed Jul 05 22:32:06 2017 +0200
@@ -51,6 +51,7 @@
 import jdk.internal.jmod.JmodFile;
 import jdk.internal.misc.JavaLangAccess;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleBootstrap;
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleHashes.HashSupplier;
 import jdk.internal.module.ModulePatcher;
@@ -80,9 +81,8 @@
                                              HashSupplier hasher) {
 
         ModuleReference mref = new ModuleReference(md, uri, supplier, hasher);
-
         if (JLA.getBootLayer() == null)
-            mref = ModulePatcher.interposeIfNeeded(mref);
+            mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
 
         return mref;
     }
@@ -93,7 +93,7 @@
     static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
         URI uri = file.toUri();
         Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHashAsString(file, a);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
         return newModule(md, uri, supplier, hasher);
     }
 
@@ -103,7 +103,7 @@
     static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
         URI uri = file.toUri();
         Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHashAsString(file, a);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
         return newModule(md, file.toUri(), supplier, hasher);
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,9 +26,12 @@
 package java.lang.module;
 
 import java.io.PrintStream;
+import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.reflect.Layer;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Deque;
 import java.util.HashMap;
@@ -47,12 +50,15 @@
 /**
  * The resolver used by {@link Configuration#resolveRequires} and
  * {@link Configuration#resolveRequiresAndUses}.
+ *
+ * @implNote The resolver is used at VM startup and so deliberately avoids
+ * using lambda and stream usages in code paths used during startup.
  */
 
 final class Resolver {
 
     private final ModuleFinder beforeFinder;
-    private final Configuration parent;
+    private final List<Configuration> parents;
     private final ModuleFinder afterFinder;
     private final PrintStream traceOutput;
 
@@ -61,11 +67,11 @@
 
 
     Resolver(ModuleFinder beforeFinder,
-             Configuration parent,
+             List<Configuration> parents,
              ModuleFinder afterFinder,
              PrintStream traceOutput) {
         this.beforeFinder = beforeFinder;
-        this.parent = parent;
+        this.parents = parents;
         this.afterFinder = afterFinder;
         this.traceOutput = traceOutput;
     }
@@ -85,10 +91,12 @@
             // find root module
             ModuleReference mref = findWithBeforeFinder(root);
             if (mref == null) {
-                if (parent.findModule(root).isPresent()) {
+
+                if (findInParent(root) != null) {
                     // in parent, nothing to do
                     continue;
                 }
+
                 mref = findWithAfterFinder(root);
                 if (mref == null) {
                     fail("Module %s not found", root);
@@ -125,13 +133,21 @@
 
             // process dependences
             for (ModuleDescriptor.Requires requires : descriptor.requires()) {
+
+                // only required at compile-time
+                if (requires.modifiers().contains(Modifier.STATIC))
+                    continue;
+
                 String dn = requires.name();
 
                 // find dependence
                 ModuleReference mref = findWithBeforeFinder(dn);
                 if (mref == null) {
-                    if (parent.findModule(dn).isPresent())
+
+                    if (findInParent(dn) != null) {
+                        // dependence is in parent
                         continue;
+                    }
 
                     mref = findWithAfterFinder(dn);
                     if (mref == null) {
@@ -174,7 +190,9 @@
             ModuleDescriptor descriptor = mref.descriptor();
             if (!descriptor.provides().isEmpty()) {
 
-                for (String sn : descriptor.provides().keySet()) {
+                for (Provides provides :  descriptor.provides()) {
+                    String sn = provides.service();
+
                     // computeIfAbsent
                     Set<ModuleReference> providers = availableProviders.get(sn);
                     if (providers == null) {
@@ -191,19 +209,23 @@
         Deque<ModuleDescriptor> q = new ArrayDeque<>();
 
         // the initial set of modules that may use services
-        Set<ModuleDescriptor> candidateConsumers = new HashSet<>();
-        Configuration p = parent;
-        while (p != null) {
-            candidateConsumers.addAll(p.descriptors());
-            p = p.parent().orElse(null);
+        Set<ModuleDescriptor> initialConsumers;
+        if (Layer.boot() == null) {
+            initialConsumers = new HashSet<>();
+        } else {
+            initialConsumers = parents.stream()
+                    .flatMap(Configuration::configurations)
+                    .distinct()
+                    .flatMap(c -> c.descriptors().stream())
+                    .collect(Collectors.toSet());
         }
         for (ModuleReference mref : nameToReference.values()) {
-            candidateConsumers.add(mref.descriptor());
+            initialConsumers.add(mref.descriptor());
         }
 
-
         // Where there is a consumer of a service then resolve all modules
         // that provide an implementation of that service
+        Set<ModuleDescriptor> candidateConsumers = initialConsumers;
         do {
             for (ModuleDescriptor descriptor : candidateConsumers) {
                 if (!descriptor.uses().isEmpty()) {
@@ -234,7 +256,6 @@
             }
 
             candidateConsumers = resolve(q);
-
         } while (!candidateConsumers.isEmpty());
 
         return this;
@@ -429,21 +450,21 @@
             for (String dn : hashes.names()) {
                 ModuleReference other = nameToReference.get(dn);
                 if (other == null) {
-                    other = parent.findModule(dn)
-                            .map(ResolvedModule::reference)
-                            .orElse(null);
+                    ResolvedModule resolvedModule = findInParent(dn);
+                    if (resolvedModule != null)
+                        other = resolvedModule.reference();
                 }
 
                 // skip checking the hash if the module has been patched
                 if (other != null && !other.isPatched()) {
-                    String recordedHash = hashes.hashFor(dn);
-                    String actualHash = other.computeHash(algorithm);
+                    byte[] recordedHash = hashes.hashFor(dn);
+                    byte[] actualHash = other.computeHash(algorithm);
                     if (actualHash == null)
                         fail("Unable to compute the hash of module %s", dn);
-                    if (!recordedHash.equals(actualHash)) {
+                    if (!Arrays.equals(recordedHash, actualHash)) {
                         fail("Hash of %s (%s) differs to expected hash (%s)" +
-                             " recorded in %s", dn, actualHash, recordedHash,
-                             descriptor.name());
+                             " recorded in %s", dn, toHexString(actualHash),
+                             toHexString(recordedHash), descriptor.name());
                     }
                 }
             }
@@ -451,52 +472,68 @@
         }
     }
 
+    private static String toHexString(byte[] ba) {
+        StringBuilder sb = new StringBuilder(ba.length * 2);
+        for (byte b: ba) {
+            sb.append(String.format("%02x", b & 0xff));
+        }
+        return sb.toString();
+    }
+
 
     /**
      * Computes the readability graph for the modules in the given Configuration.
      *
      * The readability graph is created by propagating "requires" through the
-     * "public requires" edges of the module dependence graph. So if the module
-     * dependence graph has m1 requires m2 && m2 requires public m3 then the
-     * resulting readability graph will contain m1 reads m2, m1 reads m3, and
-     * m2 reads m3.
+     * "requires transitive" edges of the module dependence graph. So if the
+     * module dependence graph has m1 requires m2 && m2 requires transitive m3
+     * then the resulting readability graph will contain m1 reads m2, m1 reads m3,
+     * and m2 reads m3.
      */
     private Map<ResolvedModule, Set<ResolvedModule>> makeGraph(Configuration cf) {
 
+        // initial capacity of maps to avoid resizing
+        int capacity = 1 + (4 * nameToReference.size())/ 3;
+
         // the "reads" graph starts as a module dependence graph and
         // is iteratively updated to be the readability graph
-        Map<ResolvedModule, Set<ResolvedModule>> g1 = new HashMap<>();
-
-        // the "requires public" graph, contains requires public edges only
-        Map<ResolvedModule, Set<ResolvedModule>> g2 = new HashMap<>();
+        Map<ResolvedModule, Set<ResolvedModule>> g1 = new HashMap<>(capacity);
 
-
-        // need "requires public" from the modules in parent configurations as
-        // there may be selected modules that have a dependency on modules in
-        // the parent configuration.
+        // the "requires transitive" graph, contains requires transitive edges only
+        Map<ResolvedModule, Set<ResolvedModule>> g2;
 
-        Configuration p = parent;
-        while (p != null) {
-            for (ModuleDescriptor descriptor : p.descriptors()) {
-                String name = descriptor.name();
-                ResolvedModule m1 = p.findModule(name)
-                    .orElseThrow(() -> new InternalError(name + " not found"));
-                for (ModuleDescriptor.Requires requires : descriptor.requires()) {
-                    if (requires.modifiers().contains(Modifier.PUBLIC)) {
-                        String dn = requires.name();
-                        ResolvedModule m2 = p.findModule(dn)
-                            .orElseThrow(() -> new InternalError(dn + " not found"));
-                        g2.computeIfAbsent(m1, k -> new HashSet<>()).add(m2);
-                    }
-                }
-            }
-
-            p = p.parent().orElse(null);
+        // need "requires transitive" from the modules in parent configurations
+        // as there may be selected modules that have a dependency on modules in
+        // the parent configuration.
+        if (Layer.boot() == null) {
+            g2 = new HashMap<>(capacity);
+        } else {
+            g2 = parents.stream()
+                .flatMap(Configuration::configurations)
+                .distinct()
+                .flatMap(c ->
+                    c.modules().stream().flatMap(m1 ->
+                        m1.descriptor().requires().stream()
+                            .filter(r -> r.modifiers().contains(Modifier.TRANSITIVE))
+                            .flatMap(r -> {
+                                Optional<ResolvedModule> m2 = c.findModule(r.name());
+                                assert m2.isPresent()
+                                        || r.modifiers().contains(Modifier.STATIC);
+                                return m2.stream();
+                            })
+                            .map(m2 -> Map.entry(m1, m2))
+                    )
+                )
+                // stream of m1->m2
+                .collect(Collectors.groupingBy(Map.Entry::getKey,
+                        HashMap::new,
+                        Collectors.mapping(Map.Entry::getValue, Collectors.toSet())
+            ));
         }
 
         // populate g1 and g2 with the dependences from the selected modules
 
-        Map<String, ResolvedModule> nameToResolved = new HashMap<>();
+        Map<String, ResolvedModule> nameToResolved = new HashMap<>(capacity);
 
         for (ModuleReference mref : nameToReference.values()) {
             ModuleDescriptor descriptor = mref.descriptor();
@@ -505,20 +542,21 @@
             ResolvedModule m1 = computeIfAbsent(nameToResolved, name, cf, mref);
 
             Set<ResolvedModule> reads = new HashSet<>();
-            Set<ResolvedModule> requiresPublic = new HashSet<>();
+            Set<ResolvedModule> requiresTransitive = new HashSet<>();
 
             for (ModuleDescriptor.Requires requires : descriptor.requires()) {
                 String dn = requires.name();
 
-                ResolvedModule m2;
+                ResolvedModule m2 = null;
                 ModuleReference mref2 = nameToReference.get(dn);
                 if (mref2 != null) {
                     // same configuration
                     m2 = computeIfAbsent(nameToResolved, dn, cf, mref2);
                 } else {
                     // parent configuration
-                    m2 = parent.findModule(dn).orElse(null);
+                    m2 = findInParent(dn);
                     if (m2 == null) {
+                        assert requires.modifiers().contains(Modifier.STATIC);
                         continue;
                     }
                 }
@@ -526,9 +564,9 @@
                 // m1 requires m2 => m1 reads m2
                 reads.add(m2);
 
-                // m1 requires public m2
-                if (requires.modifiers().contains(Modifier.PUBLIC)) {
-                    requiresPublic.add(m2);
+                // m1 requires transitive m2
+                if (requires.modifiers().contains(Modifier.TRANSITIVE)) {
+                    requiresTransitive.add(m2);
                 }
 
             }
@@ -538,7 +576,7 @@
             if (descriptor.isAutomatic()) {
 
                 // reads all selected modules
-                // `requires public` all selected automatic modules
+                // `requires transitive` all selected automatic modules
                 for (ModuleReference mref2 : nameToReference.values()) {
                     ModuleDescriptor descriptor2 = mref2.descriptor();
                     String name2 = descriptor2.name();
@@ -548,40 +586,42 @@
                             = computeIfAbsent(nameToResolved, name2, cf, mref2);
                         reads.add(m2);
                         if (descriptor2.isAutomatic())
-                            requiresPublic.add(m2);
+                            requiresTransitive.add(m2);
                     }
                 }
 
                 // reads all modules in parent configurations
-                // `requires public` all automatic modules in parent configurations
-                p = parent;
-                while (p != null) {
-                    for (ResolvedModule m : p.modules()) {
-                        reads.add(m);
-                        if (m.reference().descriptor().isAutomatic())
-                            requiresPublic.add(m);
-                    }
-                    p = p.parent().orElse(null);
+                // `requires transitive` all automatic modules in parent
+                // configurations
+                for (Configuration parent : parents) {
+                    parent.configurations()
+                            .map(Configuration::modules)
+                            .flatMap(Set::stream)
+                            .forEach(m -> {
+                                reads.add(m);
+                                if (m.reference().descriptor().isAutomatic())
+                                    requiresTransitive.add(m);
+                            });
                 }
-
             }
 
             g1.put(m1, reads);
-            g2.put(m1, requiresPublic);
+            g2.put(m1, requiresTransitive);
         }
 
-        // Iteratively update g1 until there are no more requires public to propagate
+        // Iteratively update g1 until there are no more requires transitive
+        // to propagate
         boolean changed;
-        Set<ResolvedModule> toAdd = new HashSet<>();
+        List<ResolvedModule> toAdd = new ArrayList<>();
         do {
             changed = false;
             for (Set<ResolvedModule> m1Reads : g1.values()) {
                 for (ResolvedModule m2 : m1Reads) {
-                    Set<ResolvedModule> m2RequiresPublic = g2.get(m2);
-                    if (m2RequiresPublic != null) {
-                        for (ResolvedModule m3 : m2RequiresPublic) {
+                    Set<ResolvedModule> m2RequiresTransitive = g2.get(m2);
+                    if (m2RequiresTransitive != null) {
+                        for (ResolvedModule m3 : m2RequiresTransitive) {
                             if (!m1Reads.contains(m3)) {
-                                // m1 reads m2, m2 requires public m3
+                                // m1 reads m2, m2 requires transitive m3
                                 // => need to add m1 reads m3
                                 toAdd.add(m3);
                             }
@@ -655,7 +695,7 @@
                     // source is exported to descriptor2
                     String source = export.source();
                     ModuleDescriptor other
-                        = packageToExporter.put(source, descriptor2);
+                        = packageToExporter.putIfAbsent(source, descriptor2);
 
                     if (other != null && other != descriptor2) {
                         // package might be local to descriptor1
@@ -692,12 +732,8 @@
                 }
 
                 // provides S
-                for (Map.Entry<String, ModuleDescriptor.Provides> entry :
-                        descriptor1.provides().entrySet()) {
-                    String service = entry.getKey();
-                    ModuleDescriptor.Provides provides = entry.getValue();
-
-                    String pn = packageName(service);
+                for (ModuleDescriptor.Provides provides : descriptor1.provides()) {
+                    String pn = packageName(provides.service());
                     if (!packageToExporter.containsKey(pn)) {
                         fail("Module %s does not read a module that exports %s",
                              descriptor1.name(), pn);
@@ -717,6 +753,18 @@
 
     }
 
+    /**
+     * Find a module of the given name in the parent configurations
+     */
+    private ResolvedModule findInParent(String mn) {
+        for (Configuration parent : parents) {
+            Optional<ResolvedModule> om = parent.findModule(mn);
+            if (om.isPresent())
+                return om.get();
+        }
+        return null;
+    }
+
 
     /**
      * Invokes the beforeFinder to find method to find the given module.
@@ -755,15 +803,18 @@
             if (afterModules.isEmpty())
                 return beforeModules;
 
-            if (beforeModules.isEmpty() && parent == Configuration.empty())
+            if (beforeModules.isEmpty()
+                    && parents.size() == 1
+                    && parents.get(0) == Configuration.empty())
                 return afterModules;
 
             Set<ModuleReference> result = new HashSet<>(beforeModules);
             for (ModuleReference mref : afterModules) {
                 String name = mref.descriptor().name();
                 if (!beforeFinder.find(name).isPresent()
-                        && !parent.findModule(name).isPresent())
+                        && findInParent(name) == null) {
                     result.add(mref);
+                }
             }
 
             return result;
--- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Wed Jul 05 22:32:06 2017 +0200
@@ -39,6 +39,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
@@ -53,6 +54,7 @@
 import jdk.internal.jimage.ImageReaderFactory;
 import jdk.internal.misc.JavaNetUriAccess;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleBootstrap;
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleHashes.HashSupplier;
 import jdk.internal.module.SystemModules;
@@ -64,7 +66,7 @@
  * run-time image.
  *
  * The modules linked into the run-time image are assumed to have the
- * ConcealedPackages attribute.
+ * Packages attribute.
  */
 
 class SystemModuleFinder implements ModuleFinder {
@@ -102,8 +104,11 @@
         int n = names.length;
         moduleCount.add(n);
 
-        Set<ModuleReference> mods = new HashSet<>(n);
-        Map<String, ModuleReference> map = new HashMap<>(n);
+        ModuleReference[] mods = new ModuleReference[n];
+
+        @SuppressWarnings(value = {"rawtypes", "unchecked"})
+        Entry<String, ModuleReference>[] map
+            = (Entry<String, ModuleReference>[])new Entry[n];
 
         for (int i = 0; i < n; i++) {
             ModuleDescriptor md = descriptors[i];
@@ -111,16 +116,16 @@
             // create the ModuleReference
             ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i]));
 
-            mods.add(mref);
-            map.put(names[i], mref);
+            mods[i] = mref;
+            map[i] = Map.entry(names[i], mref);
 
             // counters
             packageCount.add(md.packages().size());
             exportsCount.add(md.exports().size());
         }
 
-        modules = Collections.unmodifiableSet(mods);
-        nameToModule = map;
+        modules = Set.of(mods);
+        nameToModule = Map.ofEntries(map);
 
         initTime.addElapsedTimeFrom(t0);
     }
@@ -190,7 +195,7 @@
             new ModuleReference(md, uri, readerSupplier, hash);
 
         // may need a reference to a patched module if --patch-module specified
-        mref = ModulePatcher.interposeIfNeeded(mref);
+        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
 
         return mref;
     }
@@ -199,7 +204,7 @@
         if (isFastPathSupported()) {
             return new HashSupplier() {
                 @Override
-                public String generate(String algorithm) {
+                public byte[] generate(String algorithm) {
                     return SystemModules.MODULES_TO_HASH[index];
                 }
             };
@@ -213,7 +218,7 @@
      * It will get the recorded hashes from module-info.class.
      */
     private static class Hashes {
-        static Map<String, String> hashes = new HashMap<>();
+        static Map<String, byte[]> hashes = new HashMap<>();
 
         static void add(ModuleDescriptor descriptor) {
             Optional<ModuleHashes> ohashes = descriptor.hashes();
@@ -228,7 +233,7 @@
 
             return new HashSupplier() {
                 @Override
-                public String generate(String algorithm) {
+                public byte[] generate(String algorithm) {
                     return hashes.get(name);
                 }
             };
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,12 +25,12 @@
 
 package java.lang.reflect;
 
+import java.lang.annotation.Annotation;
 import java.security.AccessController;
 
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.reflect.ReflectionFactory;
-import java.lang.annotation.Annotation;
 
 /**
  * The AccessibleObject class is the base class for Field, Method and
@@ -81,8 +81,10 @@
      * <p>This method cannot be used to enable access to an object that is a
      * {@link Member member} of a class in a different module to the caller and
      * where the class is in a package that is not exported to the caller's
-     * module. Additionally, this method cannot be used to enable access to
-     * non-public members of {@code AccessibleObject} or {@link Module}.
+     * module. Additionally, if the member is non-public or its declaring
+     * class is non-public, then this method can only be used to enable access
+     * if the package is {@link Module#isOpen(String,Module) open} to at least
+     * the caller's module.
      *
      * <p>If there is a security manager, its
      * {@code checkPermission} method is first called with a
@@ -126,8 +128,10 @@
      * <p>This method cannot be used to enable access to an object that is a
      * {@link Member member} of a class in a different module to the caller and
      * where the class is in a package that is not exported to the caller's
-     * module. Additionally, this method cannot be used to enable access to
-     * non-public members of {@code AccessibleObject} or {@link Module}.
+     * module. Additionally, if the member is non-public or its declaring
+     * class is non-public, then this method can only be used to enable access
+     * if the package is {@link Module#isOpen(String,Module) open} to at least
+     * the caller's module.
      *
      * <p>If there is a security manager, its
      * {@code checkPermission} method is first called with a
@@ -138,6 +142,7 @@
      * @throws SecurityException if the request is denied
      * @see SecurityManager#checkPermission
      * @see ReflectPermission
+     * @see java.lang.invoke.MethodHandles#privateLookupIn
      */
     public void setAccessible(boolean flag) {
         AccessibleObject.checkPermission();
@@ -161,35 +166,39 @@
         Module callerModule = caller.getModule();
         Module declaringModule = declaringClass.getModule();
 
-        if (callerModule != declaringModule
-                && callerModule != Object.class.getModule()) {
+        if (callerModule == declaringModule) return;
+        if (callerModule == Object.class.getModule()) return;
+        if (!declaringModule.isNamed()) return;
 
-            // check exports to target module
-            String pn = packageName(declaringClass);
-            if (!declaringModule.isExported(pn, callerModule)) {
-                String msg = "Unable to make member of "
-                        + declaringClass + " accessible:  "
-                        + declaringModule + " does not export "
-                        + pn + " to " + callerModule;
-                Reflection.throwInaccessibleObjectException(msg);
-            }
-
-        }
+        // package is open to caller
+        String pn = packageName(declaringClass);
+        if (declaringModule.isOpen(pn, callerModule))
+            return;
 
-        if (declaringClass == Module.class
-                || declaringClass == AccessibleObject.class) {
-            int modifiers;
-            if (this instanceof Executable) {
-                modifiers = ((Executable) this).getModifiers();
-            } else {
-                modifiers = ((Field) this).getModifiers();
-            }
-            if (!Modifier.isPublic(modifiers)) {
-                String msg = "Cannot make a non-public member of "
-                        + declaringClass + " accessible";
-                Reflection.throwInaccessibleObjectException(msg);
-            }
+        // package is exported to caller and class/member is public
+        boolean isExported = declaringModule.isExported(pn, callerModule);
+        boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
+        int modifiers;
+        if (this instanceof Executable) {
+            modifiers = ((Executable) this).getModifiers();
+        } else {
+            modifiers = ((Field) this).getModifiers();
         }
+        boolean isMemberPublic = Modifier.isPublic(modifiers);
+        if (isExported && isClassPublic && isMemberPublic)
+            return;
+
+        // not accessible
+        String msg = "Unable to make ";
+        if (this instanceof Field)
+            msg += "field ";
+        msg += this + " accessible: " + declaringModule + " does not \"";
+        if (isClassPublic && isMemberPublic)
+            msg += "exports";
+        else
+            msg += "opens";
+        msg += " " + pn + "\" to " + callerModule;
+        Reflection.throwInaccessibleObjectException(msg);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,23 +27,29 @@
 
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ResolvedModule;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
+import jdk.internal.loader.ClassLoaderValue;
 import jdk.internal.loader.Loader;
 import jdk.internal.loader.LoaderPool;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Modules;
 import jdk.internal.module.ServicesCatalog;
-import jdk.internal.module.ServicesCatalog.ServiceProvider;
 import sun.security.util.SecurityConstants;
 
 
@@ -55,7 +61,7 @@
  * Creating a layer informs the Java virtual machine about the classes that
  * may be loaded from modules so that the Java virtual machine knows which
  * module that each class is a member of. Each layer, except the {@link
- * #empty() empty} layer, has a {@link #parent() parent}. </p>
+ * #empty() empty} layer, has at least one {@link #parents() parent}. </p>
  *
  * <p> Creating a layer creates a {@link Module} object for each {@link
  * ResolvedModule} in the configuration. For each resolved module that is
@@ -71,7 +77,11 @@
  * mapped to a single class loader or where each module is mapped to its own
  * class loader. The {@link #defineModules defineModules} method is for more
  * advanced cases where modules are mapped to custom class loaders by means of
- * a function specified to the method. </p>
+ * a function specified to the method. Each of these methods has an instance
+ * and static variant. The instance methods create a layer with the receiver
+ * as the parent layer. The static methods are for more advanced cases where
+ * there can be more than one parent layer or a {@link Layer.Controller
+ * Controller} is needed to control modules in the layer. </p>
  *
  * <p> A Java virtual machine has at least one non-empty layer, the {@link
  * #boot() boot} layer, that is created when the Java virtual machine is
@@ -80,7 +90,7 @@
  * The modules in the boot layer are mapped to the bootstrap class loader and
  * other class loaders that are <a href="../ClassLoader.html#builtinLoaders">
  * built-in</a> into the Java virtual machine. The boot layer will often be
- * the {@link #parent() parent} when creating additional layers. </p>
+ * the {@link #parents() parent} when creating additional layers. </p>
  *
  * <p> As when creating a {@code Configuration},
  * {@link ModuleDescriptor#isAutomatic() automatic} modules receive
@@ -123,30 +133,29 @@
 
     // the empty Layer
     private static final Layer EMPTY_LAYER
-        = new Layer(Configuration.empty(), null, null);
+        = new Layer(Configuration.empty(), List.of(), null);
 
     // the configuration from which this Layer was created
     private final Configuration cf;
 
-    // parent layer, null in the case of the empty layer
-    private final Layer parent;
+    // parent layers, empty in the case of the empty layer
+    private final List<Layer> parents;
 
     // maps module name to jlr.Module
     private final Map<String, Module> nameToModule;
 
-
     /**
      * Creates a new Layer from the modules in the given configuration.
      */
     private Layer(Configuration cf,
-                  Layer parent,
+                  List<Layer> parents,
                   Function<String, ClassLoader> clf)
     {
         this.cf = cf;
-        this.parent = parent;
+        this.parents = parents; // no need to do defensive copy
 
         Map<String, Module> map;
-        if (parent == null) {
+        if (parents.isEmpty()) {
             map = Collections.emptyMap();
         } else {
             map = Module.defineModules(cf, clf, this);
@@ -154,12 +163,230 @@
         this.nameToModule = map; // no need to do defensive copy
     }
 
+    /**
+     * Controls a layer. The static methods defined by {@link Layer} to create
+     * module layers return a {@code Controller} that can be used to control
+     * modules in the layer.
+     *
+     * @apiNote Care should be taken with {@code Controller} objects, they
+     * should never be shared with untrusted code.
+     *
+     * @since 9
+     */
+    public static final class Controller {
+        private final Layer layer;
+
+        Controller(Layer layer) {
+            this.layer = layer;
+        }
+
+        /**
+         * Returns the layer that this object controls.
+         *
+         * @return the layer
+         */
+        public Layer layer() {
+            return layer;
+        }
+
+        private void ensureInLayer(Module source) {
+            if (!layer.modules().contains(source))
+                throw new IllegalArgumentException(source + " not in layer");
+        }
+
+
+        /**
+         * Updates module {@code source} in the layer to read module
+         * {@code target}. This method is a no-op if {@code source} already
+         * reads {@code target}.
+         *
+         * @implNote <em>Read edges</em> added by this method are <em>weak</em>
+         * and do not prevent {@code target} from being GC'ed when {@code source}
+         * is strongly reachable.
+         *
+         * @param  source
+         *         The source module
+         * @param  target
+         *         The target module to read
+         *
+         * @return This controller
+         *
+         * @throws IllegalArgumentException
+         *         If {@code source} is not in the layer
+         *
+         * @see Module#addReads
+         */
+        public Controller addReads(Module source, Module target) {
+            Objects.requireNonNull(source);
+            Objects.requireNonNull(target);
+            ensureInLayer(source);
+            Modules.addReads(source, target);
+            return this;
+        }
+
+        /**
+         * Updates module {@code source} in the layer to open a package to
+         * module {@code target}. This method is a no-op if {@code source}
+         * already opens the package to at least {@code target}.
+         *
+         * @param  source
+         *         The source module
+         * @param  pn
+         *         The package name
+         * @param  target
+         *         The target module to read
+         *
+         * @return This controller
+         *
+         * @throws IllegalArgumentException
+         *         If {@code source} is not in the layer or the package is not
+         *         in the source module
+         *
+         * @see Module#addOpens
+         */
+        public Controller addOpens(Module source, String pn, Module target) {
+            Objects.requireNonNull(source);
+            Objects.requireNonNull(source);
+            Objects.requireNonNull(target);
+            ensureInLayer(source);
+            Modules.addOpens(source, pn, target);
+            return this;
+        }
+    }
+
 
     /**
      * Creates a new layer, with this layer as its parent, by defining the
      * modules in the given {@code Configuration} to the Java virtual machine.
      * This method creates one class loader and defines all modules to that
-     * class loader.
+     * class loader. The {@link ClassLoader#getParent() parent} of each class
+     * loader is the given parent class loader. This method works exactly as
+     * specified by the static {@link
+     * #defineModulesWithOneLoader(Configuration,List,ClassLoader)
+     * defineModulesWithOneLoader} method when invoked with this layer as the
+     * parent. In other words, if this layer is {@code thisLayer} then this
+     * method is equivalent to invoking:
+     * <pre> {@code
+     *     Layer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer();
+     * }</pre>
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  parentLoader
+     *         The parent class loader for the class loader created by this
+     *         method; may be {@code null} for the bootstrap class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws LayerInstantiationException
+     *         If all modules cannot be defined to the same class loader for any
+     *         of the reasons listed above or the layer cannot be created because
+     *         the configuration contains a module named "{@code java.base}" or
+     *         a module with a package name starting with "{@code java.}"
+     * @throws SecurityException
+     *         If {@code RuntimePermission("createClassLoader")} or
+     *         {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     *
+     * @see #findLoader
+     */
+    public Layer defineModulesWithOneLoader(Configuration cf,
+                                            ClassLoader parentLoader) {
+        return defineModulesWithOneLoader(cf, List.of(this), parentLoader).layer();
+    }
+
+
+    /**
+     * Creates a new layer, with this layer as its parent, by defining the
+     * modules in the given {@code Configuration} to the Java virtual machine.
+     * Each module is defined to its own {@link ClassLoader} created by this
+     * method. The {@link ClassLoader#getParent() parent} of each class loader
+     * is the given parent class loader. This method works exactly as specified
+     * by the static {@link
+     * #defineModulesWithManyLoaders(Configuration,List,ClassLoader)
+     * defineModulesWithManyLoaders} method when invoked with this layer as the
+     * parent. In other words, if this layer is {@code thisLayer} then this
+     * method is equivalent to invoking:
+     * <pre> {@code
+     *     Layer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer();
+     * }</pre>
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  parentLoader
+     *         The parent class loader for each of the class loaders created by
+     *         this method; may be {@code null} for the bootstrap class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws LayerInstantiationException
+     *         If the layer cannot be created because the configuration contains
+     *         a module named "{@code java.base}" or a module with a package
+     *         name starting with "{@code java.}"
+     * @throws SecurityException
+     *         If {@code RuntimePermission("createClassLoader")} or
+     *         {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     *
+     * @see #findLoader
+     */
+    public Layer defineModulesWithManyLoaders(Configuration cf,
+                                              ClassLoader parentLoader) {
+        return defineModulesWithManyLoaders(cf, List.of(this), parentLoader).layer();
+    }
+
+
+    /**
+     * Creates a new layer, with this layer as its parent, by defining the
+     * modules in the given {@code Configuration} to the Java virtual machine.
+     * Each module is mapped, by name, to its class loader by means of the
+     * given function. This method works exactly as specified by the static
+     * {@link #defineModules(Configuration,List,Function) defineModules}
+     * method when invoked with this layer as the parent. In other words, if
+     * this layer is {@code thisLayer} then this method is equivalent to
+     * invoking:
+     * <pre> {@code
+     *     Layer.defineModules(cf, List.of(thisLayer), clf).layer();
+     * }</pre>
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  clf
+     *         The function to map a module name to a class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws LayerInstantiationException
+     *         If creating the {@code Layer} fails for any of the reasons
+     *         listed above, the layer cannot be created because the
+     *         configuration contains a module named "{@code java.base}",
+     *         a module with a package name starting with "{@code java.}" is
+     *         mapped to a class loader other than the {@link
+     *         ClassLoader#getPlatformClassLoader() platform class loader},
+     *         or the function to map a module name to a class loader returns
+     *         {@code null}
+     * @throws SecurityException
+     *         If {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     */
+    public Layer defineModules(Configuration cf,
+                               Function<String, ClassLoader> clf) {
+        return defineModules(cf, List.of(this), clf).layer();
+    }
+
+    /**
+     * Creates a new layer by defining the modules in the given {@code
+     * Configuration} to the Java virtual machine. This method creates one
+     * class loader and defines all modules to that class loader.
      *
      * <p> The class loader created by this method implements <em>direct
      * delegation</em> when loading types from modules. When its {@link
@@ -180,7 +407,7 @@
      * <ul>
      *
      *     <li><p> <em>Overlapping packages</em>: Two or more modules in the
-     *     configuration have the same package (exported or concealed). </p></li>
+     *     configuration have the same package. </p></li>
      *
      *     <li><p> <em>Split delegation</em>: The resulting class loader would
      *     need to delegate to more than one class loader in order to load types
@@ -194,19 +421,22 @@
      *
      * @param  cf
      *         The configuration for the layer
+     * @param  parentLayers
+     *         The list parent layers in search order
      * @param  parentLoader
      *         The parent class loader for the class loader created by this
      *         method; may be {@code null} for the bootstrap class loader
      *
-     * @return The newly created layer
+     * @return A controller that controls the newly created layer
      *
      * @throws IllegalArgumentException
-     *         If the parent of the given configuration is not the configuration
-     *         for this layer
+     *         If the parent configurations do not match the configuration of
+     *         the parent layers, including order
      * @throws LayerInstantiationException
      *         If all modules cannot be defined to the same class loader for any
      *         of the reasons listed above or the layer cannot be created because
-     *         the configuration contains a module named "{@code java.base}"
+     *         the configuration contains a module named "{@code java.base}" or
+     *         a module with a package name starting with "{@code java.}"
      * @throws SecurityException
      *         If {@code RuntimePermission("createClassLoader")} or
      *         {@code RuntimePermission("getClassLoader")} is denied by
@@ -214,29 +444,32 @@
      *
      * @see #findLoader
      */
-    public Layer defineModulesWithOneLoader(Configuration cf,
-                                            ClassLoader parentLoader)
+    public static Controller defineModulesWithOneLoader(Configuration cf,
+                                                        List<Layer> parentLayers,
+                                                        ClassLoader parentLoader)
     {
-        checkConfiguration(cf);
+        List<Layer> parents = new ArrayList<>(parentLayers);
+        checkConfiguration(cf, parents);
+
         checkCreateClassLoaderPermission();
         checkGetClassLoaderPermission();
 
         try {
             Loader loader = new Loader(cf.modules(), parentLoader);
-            loader.initRemotePackageMap(cf, this);
-            return new Layer(cf, this, mn -> loader);
+            loader.initRemotePackageMap(cf, parents);
+            Layer layer =  new Layer(cf, parents, mn -> loader);
+            return new Controller(layer);
         } catch (IllegalArgumentException e) {
             throw new LayerInstantiationException(e.getMessage());
         }
     }
 
-
     /**
-     * Creates a new layer, with this layer as its parent, by defining the
-     * modules in the given {@code Configuration} to the Java virtual machine.
-     * Each module is defined to its own {@link ClassLoader} created by this
-     * method. The {@link ClassLoader#getParent() parent} of each class loader
-     * is the given parent class loader.
+     * Creates a new layer by defining the modules in the given {@code
+     * Configuration} to the Java virtual machine. Each module is defined to
+     * its own {@link ClassLoader} created by this method. The {@link
+     * ClassLoader#getParent() parent} of each class loader is the given parent
+     * class loader.
      *
      * <p> The class loaders created by this method implement <em>direct
      * delegation</em> when loading types from modules. When {@link
@@ -258,18 +491,21 @@
      *
      * @param  cf
      *         The configuration for the layer
+     * @param  parentLayers
+     *         The list parent layers in search order
      * @param  parentLoader
      *         The parent class loader for each of the class loaders created by
      *         this method; may be {@code null} for the bootstrap class loader
      *
-     * @return The newly created layer
+     * @return A controller that controls the newly created layer
      *
      * @throws IllegalArgumentException
-     *         If the parent of the given configuration is not the configuration
-     *         for this layer
+     *         If the parent configurations do not match the configuration of
+     *         the parent layers, including order
      * @throws LayerInstantiationException
      *         If the layer cannot be created because the configuration contains
-     *         a module named "{@code java.base}"
+     *         a module named "{@code java.base}" or a module with a package
+     *         name starting with "{@code java.}"
      * @throws SecurityException
      *         If {@code RuntimePermission("createClassLoader")} or
      *         {@code RuntimePermission("getClassLoader")} is denied by
@@ -277,37 +513,43 @@
      *
      * @see #findLoader
      */
-    public Layer defineModulesWithManyLoaders(Configuration cf,
-                                              ClassLoader parentLoader)
+    public static Controller defineModulesWithManyLoaders(Configuration cf,
+                                                          List<Layer> parentLayers,
+                                                          ClassLoader parentLoader)
     {
-        checkConfiguration(cf);
+        List<Layer> parents = new ArrayList<>(parentLayers);
+        checkConfiguration(cf, parents);
+
         checkCreateClassLoaderPermission();
         checkGetClassLoaderPermission();
 
-        LoaderPool pool = new LoaderPool(cf, this, parentLoader);
+        LoaderPool pool = new LoaderPool(cf, parents, parentLoader);
         try {
-            return new Layer(cf, this, pool::loaderFor);
+            Layer layer = new Layer(cf, parents, pool::loaderFor);
+            return new Controller(layer);
         } catch (IllegalArgumentException e) {
             throw new LayerInstantiationException(e.getMessage());
         }
     }
 
-
     /**
-     * Creates a new layer, with this layer as its parent, by defining the
-     * modules in the given {@code Configuration} to the Java virtual machine.
+     * Creates a new layer by defining the modules in the given {@code
+     * Configuration} to the Java virtual machine.
      * Each module is mapped, by name, to its class loader by means of the
      * given function. The class loader delegation implemented by these class
-     * loaders must respect module readability. In addition, the caller needs
-     * to arrange that the class loaders are ready to load from these module
-     * before there are any attempts to load classes or resources.
+     * loaders must respect module readability. The class loaders should be
+     * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
+     * avoid deadlocks during class loading. In addition, the entity creating
+     * a new layer with this method should arrange that the class loaders are
+     * ready to load from these module before there are any attempts to load
+     * classes or resources.
      *
      * <p> Creating a {@code Layer} can fail for the following reasons: </p>
      *
      * <ul>
      *
-     *     <li><p> Two or more modules with the same package (exported or
-     *     concealed) are mapped to the same class loader. </p></li>
+     *     <li><p> Two or more modules with the same package are mapped to the
+     *     same class loader. </p></li>
      *
      *     <li><p> A module is mapped to a class loader that already has a
      *     module of the same name defined to it. </p></li>
@@ -328,26 +570,35 @@
      *
      * @param  cf
      *         The configuration for the layer
+     * @param  parentLayers
+     *         The list parent layers in search order
      * @param  clf
      *         The function to map a module name to a class loader
      *
-     * @return The newly created layer
+     * @return A controller that controls the newly created layer
      *
      * @throws IllegalArgumentException
-     *         If the parent of the given configuration is not the configuration
-     *         for this layer
+     *         If the parent configurations do not match the configuration of
+     *         the parent layers, including order
      * @throws LayerInstantiationException
      *         If creating the {@code Layer} fails for any of the reasons
-     *         listed above or the layer cannot be created because the
-     *         configuration contains a module named "{@code java.base}"
+     *         listed above, the layer cannot be created because the
+     *         configuration contains a module named "{@code java.base}",
+     *         a module with a package name starting with "{@code java.}" is
+     *         mapped to a class loader other than the {@link
+     *         ClassLoader#getPlatformClassLoader() platform class loader},
+     *         or the function to map a module name to a class loader returns
+     *         {@code null}
      * @throws SecurityException
      *         If {@code RuntimePermission("getClassLoader")} is denied by
      *         the security manager
      */
-    public Layer defineModules(Configuration cf,
-                               Function<String, ClassLoader> clf)
+    public static Controller defineModules(Configuration cf,
+                                           List<Layer> parentLayers,
+                                           Function<String, ClassLoader> clf)
     {
-        checkConfiguration(cf);
+        List<Layer> parents = new ArrayList<>(parentLayers);
+        checkConfiguration(cf, parents);
         Objects.requireNonNull(clf);
 
         checkGetClassLoaderPermission();
@@ -362,7 +613,8 @@
         }
 
         try {
-            return new Layer(cf, this, clf);
+            Layer layer = new Layer(cf, parents, clf);
+            return new Controller(layer);
         } catch (IllegalArgumentException iae) {
             // IAE is thrown by VM when defining the module fails
             throw new LayerInstantiationException(iae.getMessage());
@@ -370,13 +622,26 @@
     }
 
 
-    private void checkConfiguration(Configuration cf) {
+    /**
+     * Checks that the parent configurations match the configuration of
+     * the parent layers.
+     */
+    private static void checkConfiguration(Configuration cf,
+                                           List<Layer> parentLayers)
+    {
         Objects.requireNonNull(cf);
 
-        Optional<Configuration> oparent = cf.parent();
-        if (!oparent.isPresent() || oparent.get() != this.configuration()) {
-            throw new IllegalArgumentException(
-                    "Parent of configuration != configuration of this Layer");
+        List<Configuration> parentConfigurations = cf.parents();
+        if (parentLayers.size() != parentConfigurations.size())
+            throw new IllegalArgumentException("wrong number of parents");
+
+        int index = 0;
+        for (Layer parent : parentLayers) {
+            if (parent.configuration() != parentConfigurations.get(index)) {
+                throw new IllegalArgumentException(
+                        "Parent of configuration != configuration of this Layer");
+            }
+            index++;
         }
     }
 
@@ -463,18 +728,57 @@
 
 
     /**
-     * Returns this layer's parent unless this is the {@linkplain #empty empty
-     * layer}, which has no parent.
+     * Returns the list of this layer's parents unless this is the
+     * {@linkplain #empty empty layer}, which has no parents and so an
+     * empty list is returned.
      *
-     * @return This layer's parent
+     * @return The list of this layer's parents
      */
-    public Optional<Layer> parent() {
-        return Optional.ofNullable(parent);
+    public List<Layer> parents() {
+        return parents;
     }
 
 
     /**
-     * Returns a set of the modules in this layer.
+     * Returns an ordered stream of layers. The first element is is this layer,
+     * the remaining elements are the parent layers in DFS order.
+     *
+     * @implNote For now, the assumption is that the number of elements will
+     * be very low and so this method does not use a specialized spliterator.
+     */
+    Stream<Layer> layers() {
+        List<Layer> allLayers = this.allLayers;
+        if (allLayers != null)
+            return allLayers.stream();
+
+        allLayers = new ArrayList<>();
+        Set<Layer> visited = new HashSet<>();
+        Deque<Layer> stack = new ArrayDeque<>();
+        visited.add(this);
+        stack.push(this);
+
+        while (!stack.isEmpty()) {
+            Layer layer = stack.pop();
+            allLayers.add(layer);
+
+            // push in reverse order
+            for (int i = layer.parents.size() - 1; i >= 0; i--) {
+                Layer parent = layer.parents.get(i);
+                if (!visited.contains(parent)) {
+                    visited.add(parent);
+                    stack.push(parent);
+                }
+            }
+        }
+
+        this.allLayers = allLayers = Collections.unmodifiableList(allLayers);
+        return allLayers.stream();
+    }
+
+    private volatile List<Layer> allLayers;
+
+    /**
+     * Returns the set of the modules in this layer.
      *
      * @return A possibly-empty unmodifiable set of the modules in this layer
      */
@@ -486,7 +790,11 @@
 
     /**
      * Returns the module with the given name in this layer, or if not in this
-     * layer, the {@linkplain #parent parent} layer.
+     * layer, the {@linkplain #parents parents} layers. Finding a module in
+     * parent layers is equivalent to invoking {@code findModule} on each
+     * parent, in search order, until the module is found or all parents have
+     * been searched. In a <em>tree of layers</em>  then this is equivalent to
+     * a depth-first search.
      *
      * @param  name
      *         The name of the module to find
@@ -496,17 +804,25 @@
      *         parent layer
      */
     public Optional<Module> findModule(String name) {
-        Module m = nameToModule.get(Objects.requireNonNull(name));
+        Objects.requireNonNull(name);
+        Module m = nameToModule.get(name);
         if (m != null)
             return Optional.of(m);
-        return parent().flatMap(l -> l.findModule(name));
+
+        return layers()
+                .skip(1)  // skip this layer
+                .map(l -> l.nameToModule)
+                .filter(map -> map.containsKey(name))
+                .map(map -> map.get(name))
+                .findAny();
     }
 
 
     /**
      * Returns the {@code ClassLoader} for the module with the given name. If
-     * a module of the given name is not in this layer then the {@link #parent}
-     * layer is checked.
+     * a module of the given name is not in this layer then the {@link #parents
+     * parent} layers are searched in the manner specified by {@link
+     * #findModule(String) findModule}.
      *
      * <p> If there is a security manager then its {@code checkPermission}
      * method is called with a {@code RuntimePermission("getClassLoader")}
@@ -527,20 +843,32 @@
      * @throws SecurityException if denied by the security manager
      */
     public ClassLoader findLoader(String name) {
-        Module m = nameToModule.get(Objects.requireNonNull(name));
-        if (m != null)
-            return m.getClassLoader();
-        Optional<Layer> ol = parent();
-        if (ol.isPresent())
-            return ol.get().findLoader(name);
-        throw new IllegalArgumentException("Module " + name
-                                           + " not known to this layer");
+        Optional<Module> om = findModule(name);
+
+        // can't use map(Module::getClassLoader) as class loader can be null
+        if (om.isPresent()) {
+            return om.get().getClassLoader();
+        } else {
+            throw new IllegalArgumentException("Module " + name
+                                               + " not known to this layer");
+        }
     }
 
+    /**
+     * Returns a string describing this layer.
+     *
+     * @return A possibly empty string describing this layer
+     */
+    @Override
+    public String toString() {
+        return modules().stream()
+                .map(Module::getName)
+                .collect(Collectors.joining(", "));
+    }
 
     /**
      * Returns the <em>empty</em> layer. There are no modules in the empty
-     * layer. It has no parent.
+     * layer. It has no parents.
      *
      * @return The empty layer
      */
@@ -572,39 +900,12 @@
         if (servicesCatalog != null)
             return servicesCatalog;
 
-        Map<String, Set<ServiceProvider>> map = new HashMap<>();
-        for (Module m : nameToModule.values()) {
-            ModuleDescriptor descriptor = m.getDescriptor();
-            for (Provides provides : descriptor.provides().values()) {
-                String service = provides.service();
-                Set<ServiceProvider> providers
-                    = map.computeIfAbsent(service, k -> new HashSet<>());
-                for (String pn : provides.providers()) {
-                    providers.add(new ServiceProvider(m, pn));
-                }
-            }
-        }
-
-        ServicesCatalog catalog = new ServicesCatalog() {
-            @Override
-            public void register(Module module) {
-                throw new UnsupportedOperationException();
-            }
-            @Override
-            public Set<ServiceProvider> findServices(String service) {
-                Set<ServiceProvider> providers = map.get(service);
-                if (providers == null) {
-                    return Collections.emptySet();
-                } else {
-                    return Collections.unmodifiableSet(providers);
-                }
-            }
-        };
-
         synchronized (this) {
             servicesCatalog = this.servicesCatalog;
             if (servicesCatalog == null) {
-                this.servicesCatalog = servicesCatalog = catalog;
+                servicesCatalog = ServicesCatalog.create();
+                nameToModule.values().forEach(servicesCatalog::register);
+                this.servicesCatalog = servicesCatalog;
             }
         }
 
@@ -612,4 +913,36 @@
     }
 
     private volatile ServicesCatalog servicesCatalog;
+
+
+    /**
+     * Record that this layer has at least one module defined to the given
+     * class loader.
+     */
+    void bindToLoader(ClassLoader loader) {
+        // CLV.computeIfAbsent(loader, (cl, clv) -> new CopyOnWriteArrayList<>())
+        List<Layer> list = CLV.get(loader);
+        if (list == null) {
+            list = new CopyOnWriteArrayList<>();
+            List<Layer> previous = CLV.putIfAbsent(loader, list);
+            if (previous != null) list = previous;
+        }
+        list.add(this);
+    }
+
+    /**
+     * Returns a stream of the layers that have at least one module defined to
+     * the given class loader.
+     */
+    static Stream<Layer> layers(ClassLoader loader) {
+        List<Layer> list = CLV.get(loader);
+        if (list != null) {
+            return list.stream();
+        } else {
+            return Stream.empty();
+        }
+    }
+
+    // the list of layers with modules defined to a class loader
+    private static final ClassLoaderValue<List<Layer>> CLV = new ClassLoaderValue<>();
 }
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,15 +27,18 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.annotation.Annotation;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleReference;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
-import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Version;
 import java.lang.module.ResolvedModule;
 import java.net.URI;
 import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -49,9 +52,17 @@
 
 import jdk.internal.loader.BuiltinClassLoader;
 import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.ResourceHelper;
+import jdk.internal.misc.JavaLangAccess;
 import jdk.internal.misc.JavaLangReflectModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ServicesCatalog;
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import sun.security.util.SecurityConstants;
@@ -83,7 +94,7 @@
  * @see java.lang.Class#getModule
  */
 
-public final class Module {
+public final class Module implements AnnotatedElement {
 
     // the layer that contains this module, can be null
     private final Layer layer;
@@ -113,6 +124,10 @@
 
         // define module to VM
 
+        boolean isOpen = descriptor.isOpen();
+        Version version = descriptor.version().orElse(null);
+        String vs = Objects.toString(version, null);
+        String loc = Objects.toString(uri, null);
         Set<String> packages = descriptor.packages();
         int n = packages.size();
         String[] array = new String[n];
@@ -120,11 +135,7 @@
         for (String pn : packages) {
             array[i++] = pn.replace('.', '/');
         }
-        Version version = descriptor.version().orElse(null);
-        String vs = Objects.toString(version, null);
-        String loc = Objects.toString(uri, null);
-
-        defineModule0(this, vs, loc, array);
+        defineModule0(this, isOpen, vs, loc, array);
     }
 
 
@@ -240,24 +251,24 @@
 
     // --
 
-    // the special Module to mean reads or exported to "all unnamed modules"
+    // special Module to mean "all unnamed modules"
     private static final Module ALL_UNNAMED_MODULE = new Module(null);
 
-    // special Module to mean exported to "everyone"
+    // special Module to mean "everyone"
     private static final Module EVERYONE_MODULE = new Module(null);
 
-    // exported to all modules
-    private static final Set<Module> EVERYONE = Collections.singleton(EVERYONE_MODULE);
+    // set contains EVERYONE_MODULE, used when a package is opened or
+    // exported unconditionally
+    private static final Set<Module> EVERYONE_SET = Set.of(EVERYONE_MODULE);
 
 
     // -- readability --
 
-    // the modules that this module permanently reads
-    // (will be final when the modules are defined in reverse topology order)
+    // the modules that this module reads
     private volatile Set<Module> reads;
 
     // additional module (2nd key) that some module (1st key) reflectively reads
-    private static final WeakPairMap<Module, Module, Boolean> transientReads
+    private static final WeakPairMap<Module, Module, Boolean> reflectivelyReads
         = new WeakPairMap<>();
 
 
@@ -293,13 +304,13 @@
         }
 
         // check if this module reads the other module reflectively
-        if (transientReads.containsKeyPair(this, other))
+        if (reflectivelyReads.containsKeyPair(this, other))
             return true;
 
         // if other is an unnamed module then check if this module reads
         // all unnamed modules
         if (!other.isNamed()
-            && transientReads.containsKeyPair(this, ALL_UNNAMED_MODULE))
+            && reflectivelyReads.containsKeyPair(this, ALL_UNNAMED_MODULE))
             return true;
 
         return false;
@@ -309,9 +320,13 @@
      * If the caller's module is this module then update this module to read
      * the given module.
      *
-     * This method is a no-op if {@code other} is this module (all modules can
-     * read themselves) or this module is an unnamed module (as unnamed modules
-     * read all modules).
+     * This method is a no-op if {@code other} is this module (all modules read
+     * themselves), this module is an unnamed module (as unnamed modules read
+     * all modules), or this module already reads {@code other}.
+     *
+     * @implNote <em>Read edges</em> added by this method are <em>weak</em> and
+     * do not prevent {@code other} from being GC'ed when this module is
+     * strongly reachable.
      *
      * @param  other
      *         The other module
@@ -381,30 +396,39 @@
         }
 
         // add reflective read
-        transientReads.putIfAbsent(this, other, Boolean.TRUE);
+        reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
     }
 
 
-    // -- exports --
+    // -- exported and open packages --
+
+    // the packages are open to other modules, can be null
+    // if the value contains EVERYONE_MODULE then the package is open to all
+    private volatile Map<String, Set<Module>> openPackages;
 
-    // the packages that are permanently exported
-    // (will be final when the modules are defined in reverse topology order)
-    private volatile Map<String, Set<Module>> exports;
+    // the packages that are exported, can be null
+    // if the value contains EVERYONE_MODULE then the package is exported to all
+    private volatile Map<String, Set<Module>> exportedPackages;
 
-    // additional exports added at run-time
-    // this module (1st key), other module (2nd key), exported packages (value)
+    // additional exports or opens added at run-time
+    // this module (1st key), other module (2nd key)
+    // (package name, open?) (value)
     private static final WeakPairMap<Module, Module, Map<String, Boolean>>
-        transientExports = new WeakPairMap<>();
+        reflectivelyExports = new WeakPairMap<>();
 
 
     /**
      * Returns {@code true} if this module exports the given package to at
      * least the given module.
      *
-     * <p> This method always return {@code true} when invoked on an unnamed
+     * <p> This method returns {@code true} if invoked to test if a package in
+     * this module is exported to itself. It always returns {@code true} when
+     * invoked on an unnamed module. A package that is {@link #isOpen open} to
+     * the given module is considered exported to that module at run-time and
+     * so this method returns {@code true} if the package is open to the given
      * module. </p>
      *
-     * <p> This method does not check if the given module reads this module </p>
+     * <p> This method does not check if the given module reads this module. </p>
      *
      * @param  pn
      *         The package name
@@ -413,93 +437,196 @@
      *
      * @return {@code true} if this module exports the package to at least the
      *         given module
+     *
+     * @see ModuleDescriptor#exports()
+     * @see #addExports(String,Module)
      */
     public boolean isExported(String pn, Module other) {
         Objects.requireNonNull(pn);
         Objects.requireNonNull(other);
-        return implIsExported(pn, other);
+        return implIsExportedOrOpen(pn, other, /*open*/false);
+    }
+
+    /**
+     * Returns {@code true} if this module has <em>opened</em> a package to at
+     * least the given module.
+     *
+     * <p> This method returns {@code true} if invoked to test if a package in
+     * this module is open to itself. It returns {@code true} when invoked on an
+     * {@link ModuleDescriptor#isOpen open} module with a package in the module.
+     * It always returns {@code true} when invoked on an unnamed module. </p>
+     *
+     * <p> This method does not check if the given module reads this module. </p>
+     *
+     * @param  pn
+     *         The package name
+     * @param  other
+     *         The other module
+     *
+     * @return {@code true} if this module has <em>opened</em> the package
+     *         to at least the given module
+     *
+     * @see ModuleDescriptor#opens()
+     * @see #addOpens(String,Module)
+     * @see AccessibleObject#setAccessible(boolean)
+     * @see java.lang.invoke.MethodHandles#privateLookupIn
+     */
+    public boolean isOpen(String pn, Module other) {
+        Objects.requireNonNull(pn);
+        Objects.requireNonNull(other);
+        return implIsExportedOrOpen(pn, other, /*open*/true);
     }
 
     /**
      * Returns {@code true} if this module exports the given package
      * unconditionally.
      *
-     * <p> This method always return {@code true} when invoked on an unnamed
-     * module. </p>
+     * <p> This method always returns {@code true} when invoked on an unnamed
+     * module. A package that is {@link #isOpen(String) opened} unconditionally
+     * is considered exported unconditionally at run-time and so this method
+     * returns {@code true} if the package is opened unconditionally. </p>
      *
-     * <p> This method does not check if the given module reads this module </p>
+     * <p> This method does not check if the given module reads this module. </p>
      *
      * @param  pn
      *         The package name
      *
      * @return {@code true} if this module exports the package unconditionally
+     *
+     * @see ModuleDescriptor#exports()
      */
     public boolean isExported(String pn) {
         Objects.requireNonNull(pn);
-        return implIsExported(pn, EVERYONE_MODULE);
+        return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/false);
     }
 
     /**
-     * Returns {@code true} if this module exports the given package to the
-     * given module. If the other module is {@code EVERYONE_MODULE} then
-     * this method tests if the package is exported unconditionally.
+     * Returns {@code true} if this module has <em>opened</em> a package
+     * unconditionally.
+     *
+     * <p> This method always returns {@code true} when invoked on an unnamed
+     * module. Additionally, it always returns {@code true} when invoked on an
+     * {@link ModuleDescriptor#isOpen open} module with a package in the
+     * module. </p>
+     *
+     * <p> This method does not check if the given module reads this module. </p>
+     *
+     * @param  pn
+     *         The package name
+     *
+     * @return {@code true} if this module has <em>opened</em> the package
+     *         unconditionally
+     *
+     * @see ModuleDescriptor#opens()
      */
-    private boolean implIsExported(String pn, Module other) {
+    public boolean isOpen(String pn) {
+        Objects.requireNonNull(pn);
+        return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/true);
+    }
+
 
-        // all packages are exported by unnamed modules
+    /**
+     * Returns {@code true} if this module exports or opens the given package
+     * to the given module. If the other module is {@code EVERYONE_MODULE} then
+     * this method tests if the package is exported or opened unconditionally.
+     */
+    private boolean implIsExportedOrOpen(String pn, Module other, boolean open) {
+        // all packages in unnamed modules are open
         if (!isNamed())
             return true;
 
-        // exported via module declaration/descriptor
-        if (isExportedPermanently(pn, other))
+        // all packages are exported/open to self
+        if (other == this && containsPackage(pn))
             return true;
 
-        // exported via addExports
-        if (isExportedReflectively(pn, other))
+        // all packages in open modules are open
+        if (descriptor.isOpen())
+            return containsPackage(pn);
+
+        // exported/opened via module declaration/descriptor
+        if (isStaticallyExportedOrOpen(pn, other, open))
             return true;
 
-        // not exported or not exported to other
+        // exported via addExports/addOpens
+        if (isReflectivelyExportedOrOpen(pn, other, open))
+            return true;
+
+        // not exported or open to other
         return false;
     }
 
     /**
-     * Returns {@code true} if this module permanently exports the given
-     * package to the given module.
+     * Returns {@code true} if this module exports or opens a package to
+     * the given module via its module declaration.
      */
-    private boolean isExportedPermanently(String pn, Module other) {
-        Map<String, Set<Module>> exports = this.exports;
-        if (exports != null) {
-            Set<Module> targets = exports.get(pn);
+    private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
+        // package is open to everyone or <other>
+        Map<String, Set<Module>> openPackages = this.openPackages;
+        if (openPackages != null) {
+            Set<Module> targets = openPackages.get(pn);
+            if (targets != null) {
+                if (targets.contains(EVERYONE_MODULE))
+                    return true;
+                if (other != EVERYONE_MODULE && targets.contains(other))
+                    return true;
+            }
+        }
 
-            if ((targets != null)
-                && (targets.contains(other) || targets.contains(EVERYONE_MODULE)))
-                return true;
+        if (!open) {
+            // package is exported to everyone or <other>
+            Map<String, Set<Module>> exportedPackages = this.exportedPackages;
+            if (exportedPackages != null) {
+                Set<Module> targets = exportedPackages.get(pn);
+                if (targets != null) {
+                    if (targets.contains(EVERYONE_MODULE))
+                        return true;
+                    if (other != EVERYONE_MODULE && targets.contains(other))
+                        return true;
+                }
+            }
         }
+
         return false;
     }
 
+
     /**
-     * Returns {@code true} if this module reflectively exports the given
+     * Returns {@code true} if this module reflectively exports or opens given
      * package package to the given module.
      */
-    private boolean isExportedReflectively(String pn, Module other) {
-        // exported to all modules
-        Map<String, ?> exports = transientExports.get(this, EVERYONE_MODULE);
-        if (exports != null && exports.containsKey(pn))
-            return true;
+    private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) {
+        // exported or open to all modules
+        Map<String, Boolean> exports = reflectivelyExports.get(this, EVERYONE_MODULE);
+        if (exports != null) {
+            Boolean b = exports.get(pn);
+            if (b != null) {
+                boolean isOpen = b.booleanValue();
+                if (!open || isOpen) return true;
+            }
+        }
 
         if (other != EVERYONE_MODULE) {
 
-            // exported to other
-            exports = transientExports.get(this, other);
-            if (exports != null && exports.containsKey(pn))
-                return true;
+            // exported or open to other
+            exports = reflectivelyExports.get(this, other);
+            if (exports != null) {
+                Boolean b = exports.get(pn);
+                if (b != null) {
+                    boolean isOpen = b.booleanValue();
+                    if (!open || isOpen) return true;
+                }
+            }
 
-            // other is an unnamed module && exported to all unnamed
+            // other is an unnamed module && exported or open to all unnamed
             if (!other.isNamed()) {
-                exports = transientExports.get(this, ALL_UNNAMED_MODULE);
-                if (exports != null && exports.containsKey(pn))
-                    return true;
+                exports = reflectivelyExports.get(this, ALL_UNNAMED_MODULE);
+                if (exports != null) {
+                    Boolean b = exports.get(pn);
+                    if (b != null) {
+                        boolean isOpen = b.booleanValue();
+                        if (!open || isOpen) return true;
+                    }
+                }
             }
 
         }
@@ -510,11 +637,11 @@
 
     /**
      * If the caller's module is this module then update this module to export
-     * package {@code pn} to the given module.
+     * the given package to the given module.
      *
-     * <p> This method has no effect if the package is already exported to the
-     * given module. It also has no effect if invoked on an unnamed module (as
-     * unnamed modules export all packages). </p>
+     * <p> This method has no effect if the package is already exported (or
+     * <em>open</em>) to the given module. It also has no effect if
+     * invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
      *
      * @param  pn
      *         The package name
@@ -528,6 +655,8 @@
      *         package {@code pn} is not a package in this module
      * @throws IllegalStateException
      *         If this is a named module and the caller is not this module
+     *
+     * @see #isExported(String,Module)
      */
     @CallerSensitive
     public Module addExports(String pn, Module other) {
@@ -535,18 +664,66 @@
             throw new IllegalArgumentException("package is null");
         Objects.requireNonNull(other);
 
-        if (isNamed()) {
+        if (isNamed() && !descriptor.isOpen()) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this) {
                 throw new IllegalStateException(caller + " != " + this);
             }
-            implAddExports(pn, other, true);
+            implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true);
         }
 
         return this;
     }
 
     /**
+     * If the caller's module is this module then update this module to
+     * <em>open</em> the given package to the given module.
+     * Opening a package with this method allows all types in the package,
+     * and all their members, not just public types and their public members,
+     * to be reflected on by the given module when using APIs that support
+     * private access or a way to bypass or suppress default Java language
+     * access control checks.
+     *
+     * <p> This method has no effect if the package is already <em>open</em>
+     * to the given module. It also has no effect if invoked on an {@link
+     * ModuleDescriptor#isOpen open} module. </p>
+     *
+     * @param  pn
+     *         The package name
+     * @param  other
+     *         The module
+     *
+     * @return this module
+     *
+     * @throws IllegalArgumentException
+     *         If {@code pn} is {@code null}, or this is a named module and the
+     *         package {@code pn} is not a package in this module
+     * @throws IllegalStateException
+     *         If this is a named module and the caller is not this module
+     *
+     * @see #isOpen(String,Module)
+     * @see AccessibleObject#setAccessible(boolean)
+     * @see java.lang.invoke.MethodHandles#privateLookupIn
+     */
+    @CallerSensitive
+    public Module addOpens(String pn, Module other) {
+        if (pn == null)
+            throw new IllegalArgumentException("package is null");
+        Objects.requireNonNull(other);
+
+        if (isNamed() && !descriptor.isOpen()) {
+            Module caller = Reflection.getCallerClass().getModule();
+            if (caller != this) {
+                throw new IllegalStateException(caller + " != " + this);
+            }
+            implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
+        }
+
+        return this;
+    }
+
+
+    /**
      * Updates the exports so that package {@code pn} is exported to module
      * {@code other} but without notifying the VM.
      *
@@ -555,7 +732,7 @@
     void implAddExportsNoSync(String pn, Module other) {
         if (other == null)
             other = EVERYONE_MODULE;
-        implAddExports(pn.replace('/', '.'), other, false);
+        implAddExportsOrOpens(pn.replace('/', '.'), other, false, false);
     }
 
     /**
@@ -565,25 +742,36 @@
      * @apiNote This method is for white-box testing.
      */
     void implAddExports(String pn, Module other) {
-        implAddExports(pn, other, true);
+        implAddExportsOrOpens(pn, other, false, true);
     }
 
     /**
-     * Updates the exports so that package {@code pn} is exported to module
-     * {@code other}.
+     * Updates the module to open package {@code pn} to module {@code other}.
+     *
+     * @apiNote This method is for white-box tests and jtreg
+     */
+    void implAddOpens(String pn, Module other) {
+        implAddExportsOrOpens(pn, other, true, true);
+    }
+
+    /**
+     * Updates a module to export or open a module to another module.
      *
      * If {@code syncVM} is {@code true} then the VM is notified.
      */
-    private void implAddExports(String pn, Module other, boolean syncVM) {
+    private void implAddExportsOrOpens(String pn,
+                                       Module other,
+                                       boolean open,
+                                       boolean syncVM) {
         Objects.requireNonNull(other);
         Objects.requireNonNull(pn);
 
-        // unnamed modules export all packages
-        if (!isNamed())
+        // all packages are open in unnamed and open modules
+        if (!isNamed() || descriptor.isOpen())
             return;
 
-        // nothing to do if already exported to other
-        if (implIsExported(pn, other))
+        // nothing to do if already exported/open to other
+        if (implIsExportedOrOpen(pn, other, open))
             return;
 
         // can only export a package in the module
@@ -604,18 +792,23 @@
             }
         }
 
-        // add package name to transientExports if absent
-        transientExports
+        // add package name to reflectivelyExports if absent
+        Map<String, Boolean> map = reflectivelyExports
             .computeIfAbsent(this, other,
-                             (_this, _other) -> new ConcurrentHashMap<>())
-            .putIfAbsent(pn, Boolean.TRUE);
+                             (m1, m2) -> new ConcurrentHashMap<>());
+
+        if (open) {
+            map.put(pn, Boolean.TRUE);  // may need to promote from FALSE to TRUE
+        } else {
+            map.putIfAbsent(pn, Boolean.FALSE);
+        }
     }
 
 
     // -- services --
 
     // additional service type (2nd key) that some module (1st key) uses
-    private static final WeakPairMap<Module, Class<?>, Boolean> transientUses
+    private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses
         = new WeakPairMap<>();
 
     /**
@@ -624,13 +817,13 @@
      * for use by frameworks that invoke {@link java.util.ServiceLoader
      * ServiceLoader} on behalf of other modules or where the framework is
      * passed a reference to the service type by other code. This method is
-     * a no-op when invoked on an unnamed module.
+     * a no-op when invoked on an unnamed module or an automatic module.
      *
      * <p> This method does not cause {@link
      * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be
      * re-run. </p>
      *
-     * @param  st
+     * @param  service
      *         The service type
      *
      * @return this module
@@ -642,39 +835,45 @@
      * @see ModuleDescriptor#uses()
      */
     @CallerSensitive
-    public Module addUses(Class<?> st) {
-        Objects.requireNonNull(st);
+    public Module addUses(Class<?> service) {
+        Objects.requireNonNull(service);
 
-        if (isNamed()) {
-
+        if (isNamed() && !descriptor.isAutomatic()) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this) {
                 throw new IllegalStateException(caller + " != " + this);
             }
-
-            if (!canUse(st)) {
-                transientUses.putIfAbsent(this, st, Boolean.TRUE);
-            }
-
+            implAddUses(service);
         }
 
         return this;
     }
 
     /**
+     * Update this module to add a service dependence on the given service
+     * type.
+     */
+    void implAddUses(Class<?> service) {
+        if (!canUse(service)) {
+            reflectivelyUses.putIfAbsent(this, service, Boolean.TRUE);
+        }
+    }
+
+
+    /**
      * Indicates if this module has a service dependence on the given service
      * type. This method always returns {@code true} when invoked on an unnamed
-     * module.
+     * module or an automatic module.
      *
-     * @param  st
+     * @param  service
      *         The service type
      *
      * @return {@code true} if this module uses service type {@code st}
      *
      * @see #addUses(Class)
      */
-    public boolean canUse(Class<?> st) {
-        Objects.requireNonNull(st);
+    public boolean canUse(Class<?> service) {
+        Objects.requireNonNull(service);
 
         if (!isNamed())
             return true;
@@ -683,11 +882,11 @@
             return true;
 
         // uses was declared
-        if (descriptor.uses().contains(st.getName()))
+        if (descriptor.uses().contains(service.getName()))
             return true;
 
         // uses added via addUses
-        return transientUses.containsKeyPair(this, st);
+        return reflectivelyUses.containsKeyPair(this, service);
     }
 
 
@@ -780,8 +979,12 @@
      * If {@code syncVM} is {@code true} then the VM is notified.
      */
     private void implAddPackage(String pn, boolean syncVM) {
-        if (pn.length() == 0)
-            throw new IllegalArgumentException("<unnamed> package not allowed");
+        if (!isNamed())
+            throw new InternalError("adding package to unnamed module?");
+        if (descriptor.isOpen())
+            throw new InternalError("adding package to open module?");
+        if (pn.isEmpty())
+            throw new InternalError("adding <unnamed> package to module?");
 
         if (descriptor.packages().contains(pn)) {
             // already in module
@@ -822,28 +1025,7 @@
     // -- creating Module objects --
 
     /**
-     * Find the runtime Module corresponding to the given ResolvedModule
-     * in the given parent Layer (or its parents).
-     */
-    private static Module find(ResolvedModule resolvedModule, Layer layer) {
-        Configuration cf = resolvedModule.configuration();
-        String dn = resolvedModule.name();
-
-        Module m = null;
-        while (layer != null) {
-            if (layer.configuration() == cf) {
-                Optional<Module> om = layer.findModule(dn);
-                m = om.get();
-                assert m.getLayer() == layer;
-                break;
-            }
-            layer = layer.parent().orElse(null);
-        }
-        return m;
-    }
-
-    /**
-     * Defines each of the module in the given configuration to the runtime.
+     * Defines all module in a configuration to the runtime.
      *
      * @return a map of module name to runtime {@code Module}
      *
@@ -854,26 +1036,40 @@
                                              Function<String, ClassLoader> clf,
                                              Layer layer)
     {
-        Map<String, Module> modules = new HashMap<>();
-        Map<String, ClassLoader> loaders = new HashMap<>();
+        Map<String, Module> nameToModule = new HashMap<>();
+        Map<String, ClassLoader> moduleToLoader = new HashMap<>();
+
+        boolean isBootLayer = (Layer.boot() == null);
+        Set<ClassLoader> loaders = new HashSet<>();
+
+        // map each module to a class loader
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            String name = resolvedModule.name();
+            ClassLoader loader = clf.apply(name);
+            if (loader != null) {
+                moduleToLoader.put(name, loader);
+                loaders.add(loader);
+            } else if (!isBootLayer) {
+                throw new IllegalArgumentException("loader can't be 'null'");
+            }
+        }
 
         // define each module in the configuration to the VM
         for (ResolvedModule resolvedModule : cf.modules()) {
             ModuleReference mref = resolvedModule.reference();
             ModuleDescriptor descriptor = mref.descriptor();
             String name = descriptor.name();
-            ClassLoader loader = clf.apply(name);
             URI uri = mref.location().orElse(null);
-
+            ClassLoader loader = moduleToLoader.get(resolvedModule.name());
             Module m;
-            if (loader == null && name.equals("java.base") && Layer.boot() == null) {
+            if (loader == null && isBootLayer && name.equals("java.base")) {
+                // java.base is already defined to the VM
                 m = Object.class.getModule();
             } else {
                 m = new Module(layer, loader, descriptor, uri);
             }
-
-            modules.put(name, m);
-            loaders.put(name, loader);
+            nameToModule.put(name, m);
+            moduleToLoader.put(name, loader);
         }
 
         // setup readability and exports
@@ -882,20 +1078,24 @@
             ModuleDescriptor descriptor = mref.descriptor();
 
             String mn = descriptor.name();
-            Module m = modules.get(mn);
+            Module m = nameToModule.get(mn);
             assert m != null;
 
             // reads
             Set<Module> reads = new HashSet<>();
-            for (ResolvedModule d : resolvedModule.reads()) {
-                Module m2;
-                if (d.configuration() == cf) {
-                    String dn = d.reference().descriptor().name();
-                    m2 = modules.get(dn);
-                    assert m2 != null;
+            for (ResolvedModule other : resolvedModule.reads()) {
+                Module m2 = null;
+                if (other.configuration() == cf) {
+                    String dn = other.reference().descriptor().name();
+                    m2 = nameToModule.get(dn);
                 } else {
-                    m2 = find(d, layer.parent().orElse(null));
+                    for (Layer parent: layer.parents()) {
+                        m2 = findModule(parent, other);
+                        if (m2 != null)
+                            break;
+                    }
                 }
+                assert m2 != null;
 
                 reads.add(m2);
 
@@ -904,64 +1104,273 @@
             }
             m.reads = reads;
 
-            // automatic modules reads all unnamed modules
+            // automatic modules read all unnamed modules
             if (descriptor.isAutomatic()) {
                 m.implAddReads(ALL_UNNAMED_MODULE, true);
             }
 
-            // exports
-            Map<String, Set<Module>> exports = new HashMap<>();
-            for (Exports export : descriptor.exports()) {
-                String source = export.source();
-                String sourceInternalForm = source.replace('.', '/');
-
-                if (export.isQualified()) {
+            // exports and opens
+            initExportsAndOpens(descriptor, nameToModule, m);
+        }
 
-                    // qualified export
-                    Set<Module> targets = new HashSet<>();
-                    for (String target : export.targets()) {
-                        // only export to modules that are in this configuration
-                        Module m2 = modules.get(target);
-                        if (m2 != null) {
-                            targets.add(m2);
-                            addExports0(m, sourceInternalForm, m2);
-                        }
+        // register the modules in the boot layer
+        if (isBootLayer) {
+            for (ResolvedModule resolvedModule : cf.modules()) {
+                ModuleReference mref = resolvedModule.reference();
+                ModuleDescriptor descriptor = mref.descriptor();
+                if (!descriptor.provides().isEmpty()) {
+                    String name = descriptor.name();
+                    Module m = nameToModule.get(name);
+                    ClassLoader loader = moduleToLoader.get(name);
+                    ServicesCatalog catalog;
+                    if (loader == null) {
+                        catalog = BootLoader.getServicesCatalog();
+                    } else {
+                        catalog = ServicesCatalog.getServicesCatalog(loader);
                     }
-                    if (!targets.isEmpty()) {
-                        exports.put(source, targets);
-                    }
-
-                } else {
-
-                    // unqualified export
-                    exports.put(source, EVERYONE);
-                    addExportsToAll0(m, sourceInternalForm);
+                    catalog.register(m);
                 }
             }
-            m.exports = exports;
+        }
+
+        // record that there is a layer with modules defined to the class loader
+        for (ClassLoader loader : loaders) {
+            layer.bindToLoader(loader);
         }
 
-        // register the modules in the service catalog if they provide services
-        for (ResolvedModule resolvedModule : cf.modules()) {
-            ModuleReference mref = resolvedModule.reference();
-            ModuleDescriptor descriptor = mref.descriptor();
-            Map<String, Provides> services = descriptor.provides();
-            if (!services.isEmpty()) {
-                String name = descriptor.name();
-                Module m = modules.get(name);
-                ClassLoader loader = loaders.get(name);
-                ServicesCatalog catalog;
-                if (loader == null) {
-                    catalog = BootLoader.getServicesCatalog();
-                } else {
-                    catalog = SharedSecrets.getJavaLangAccess()
-                                           .createOrGetServicesCatalog(loader);
+        return nameToModule;
+    }
+
+
+    /**
+     * Find the runtime Module corresponding to the given ResolvedModule
+     * in the given parent layer (or its parents).
+     */
+    private static Module findModule(Layer parent, ResolvedModule resolvedModule) {
+        Configuration cf = resolvedModule.configuration();
+        String dn = resolvedModule.name();
+        return parent.layers()
+                .filter(l -> l.configuration() == cf)
+                .findAny()
+                .map(layer -> {
+                    Optional<Module> om = layer.findModule(dn);
+                    assert om.isPresent() : dn + " not found in layer";
+                    Module m = om.get();
+                    assert m.getLayer() == layer : m + " not in expected layer";
+                    return m;
+                })
+                .orElse(null);
+    }
+
+    /**
+     * Initialize the maps of exported and open packages for module m.
+     */
+    private static void initExportsAndOpens(ModuleDescriptor descriptor,
+                                            Map<String, Module> nameToModule,
+                                            Module m)
+    {
+        // The VM doesn't know about open modules so need to export all packages
+        if (descriptor.isOpen()) {
+            assert descriptor.opens().isEmpty();
+            for (String source : descriptor.packages()) {
+                String sourceInternalForm = source.replace('.', '/');
+                addExportsToAll0(m, sourceInternalForm);
+            }
+            return;
+        }
+
+        Map<String, Set<Module>> openPackages = new HashMap<>();
+        Map<String, Set<Module>> exportedPackages = new HashMap<>();
+
+        // process the open packages first
+        for (Opens opens : descriptor.opens()) {
+            String source = opens.source();
+            String sourceInternalForm = source.replace('.', '/');
+
+            if (opens.isQualified()) {
+                // qualified opens
+                Set<Module> targets = new HashSet<>();
+                for (String target : opens.targets()) {
+                    // only open to modules that are in this configuration
+                    Module m2 = nameToModule.get(target);
+                    if (m2 != null) {
+                        addExports0(m, sourceInternalForm, m2);
+                        targets.add(m2);
+                    }
                 }
-                catalog.register(m);
+                if (!targets.isEmpty()) {
+                    openPackages.put(source, targets);
+                }
+            } else {
+                // unqualified opens
+                addExportsToAll0(m, sourceInternalForm);
+                openPackages.put(source, EVERYONE_SET);
             }
         }
 
-        return modules;
+        // next the exports, skipping exports when the package is open
+        for (Exports exports : descriptor.exports()) {
+            String source = exports.source();
+            String sourceInternalForm = source.replace('.', '/');
+
+            // skip export if package is already open to everyone
+            Set<Module> openToTargets = openPackages.get(source);
+            if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE))
+                continue;
+
+            if (exports.isQualified()) {
+                // qualified exports
+                Set<Module> targets = new HashSet<>();
+                for (String target : exports.targets()) {
+                    // only export to modules that are in this configuration
+                    Module m2 = nameToModule.get(target);
+                    if (m2 != null) {
+                        // skip qualified export if already open to m2
+                        if (openToTargets == null || !openToTargets.contains(m2)) {
+                            addExports0(m, sourceInternalForm, m2);
+                            targets.add(m2);
+                        }
+                    }
+                }
+                if (!targets.isEmpty()) {
+                    exportedPackages.put(source, targets);
+                }
+
+            } else {
+                // unqualified exports
+                addExportsToAll0(m, sourceInternalForm);
+                exportedPackages.put(source, EVERYONE_SET);
+            }
+        }
+
+        if (!openPackages.isEmpty())
+            m.openPackages = openPackages;
+        if (!exportedPackages.isEmpty())
+            m.exportedPackages = exportedPackages;
+    }
+
+
+    // -- annotations --
+
+    /**
+     * {@inheritDoc}
+     * This method returns {@code null} when invoked on an unnamed module.
+     */
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        return moduleInfoClass().getDeclaredAnnotation(annotationClass);
+    }
+
+    /**
+     * {@inheritDoc}
+     * This method returns an empty array when invoked on an unnamed module.
+     */
+    @Override
+    public Annotation[] getAnnotations() {
+        return moduleInfoClass().getAnnotations();
+    }
+
+    /**
+     * {@inheritDoc}
+     * This method returns an empty array when invoked on an unnamed module.
+     */
+    @Override
+    public Annotation[] getDeclaredAnnotations() {
+        return moduleInfoClass().getDeclaredAnnotations();
+    }
+
+    // cached class file with annotations
+    private volatile Class<?> moduleInfoClass;
+
+    private Class<?> moduleInfoClass() {
+        Class<?> clazz = this.moduleInfoClass;
+        if (clazz != null)
+            return clazz;
+
+        synchronized (this) {
+            clazz = this.moduleInfoClass;
+            if (clazz == null) {
+                if (isNamed()) {
+                    PrivilegedAction<Class<?>> pa = this::loadModuleInfoClass;
+                    clazz = AccessController.doPrivileged(pa);
+                }
+                if (clazz == null) {
+                    class DummyModuleInfo { }
+                    clazz = DummyModuleInfo.class;
+                }
+                this.moduleInfoClass = clazz;
+            }
+            return clazz;
+        }
+    }
+
+    private Class<?> loadModuleInfoClass() {
+        Class<?> clazz = null;
+        try (InputStream in = getResourceAsStream("module-info.class")) {
+            if (in != null)
+                clazz = loadModuleInfoClass(in);
+        } catch (Exception ignore) { }
+        return clazz;
+    }
+
+    /**
+     * Loads module-info.class as a package-private interface in a class loader
+     * that is a child of this module's class loader.
+     */
+    private Class<?> loadModuleInfoClass(InputStream in) throws IOException {
+        final String MODULE_INFO = "module-info";
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+
+        ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) {
+            @Override
+            public void visit(int version,
+                              int access,
+                              String name,
+                              String signature,
+                              String superName,
+                              String[] interfaces) {
+                cw.visit(version,
+                        Opcodes.ACC_INTERFACE
+                            + Opcodes.ACC_ABSTRACT
+                            + Opcodes.ACC_SYNTHETIC,
+                        MODULE_INFO,
+                        null,
+                        "java/lang/Object",
+                        null);
+            }
+            @Override
+            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+                // keep annotations
+                return super.visitAnnotation(desc, visible);
+            }
+            @Override
+            public void visitAttribute(Attribute attr) {
+                // drop non-annotation attributes
+            }
+        };
+
+        ClassReader cr = new ClassReader(in);
+        cr.accept(cv, 0);
+        byte[] bytes = cw.toByteArray();
+
+        ClassLoader cl = new ClassLoader(loader) {
+            @Override
+            protected Class<?> findClass(String cn)throws ClassNotFoundException {
+                if (cn.equals(MODULE_INFO)) {
+                    return super.defineClass(cn, bytes, 0, bytes.length);
+                } else {
+                    throw new ClassNotFoundException(cn);
+                }
+            }
+        };
+
+        try {
+            return cl.loadClass(MODULE_INFO);
+        } catch (ClassNotFoundException e) {
+            throw new InternalError(e);
+        }
     }
 
 
@@ -969,16 +1378,35 @@
 
 
     /**
-     * Returns an input stream for reading a resource in this module. Returns
-     * {@code null} if the resource is not in this module or access to the
-     * resource is denied by the security manager.
-     * The {@code name} is a {@code '/'}-separated path name that identifies
-     * the resource.
+     * Returns an input stream for reading a resource in this module. The
+     * {@code name} parameter is a {@code '/'}-separated path name that
+     * identifies the resource.
+     *
+     * <p> A resource in a named modules may be <em>encapsulated</em> so that
+     * it cannot be located by code in other modules. Whether a resource can be
+     * located or not is determined as follows:
+     *
+     * <ul>
+     *     <li> The <em>package name</em> of the resource is derived from the
+     *     subsequence of characters that precedes the last {@code '/'} and then
+     *     replacing each {@code '/'} character in the subsequence with
+     *     {@code '.'}. For example, the package name derived for a resource
+     *     named "{@code a/b/c/foo.properties}" is "{@code a.b.c}". </li>
      *
-     * <p> If this module is an unnamed module, and the {@code ClassLoader} for
-     * this module is not {@code null}, then this method is equivalent to
-     * invoking the {@link ClassLoader#getResourceAsStream(String)
-     * getResourceAsStream} method on the class loader for this module.
+     *     <li> If the package name is a package in the module then the package
+     *     must be {@link #isOpen open} the module of the caller of this method.
+     *     If the package is not in the module then the resource is not
+     *     encapsulated. Resources in the unnamed package or "{@code META-INF}",
+     *     for example, are never encapsulated because they can never be
+     *     packages in a named module. </li>
+     *
+     *     <li> As a special case, resources ending with "{@code .class}" are
+     *     never encapsulated. </li>
+     * </ul>
+     *
+     * <p> This method returns {@code null} if the resource is not in this
+     * module, the resource is encapsulated and cannot be located by the caller,
+     * or access to the resource is denied by the security manager.
      *
      * @param  name
      *         The resource name
@@ -990,36 +1418,35 @@
      *
      * @see java.lang.module.ModuleReader#open(String)
      */
+    @CallerSensitive
     public InputStream getResourceAsStream(String name) throws IOException {
         Objects.requireNonNull(name);
 
-        URL url = null;
-
-        if (isNamed()) {
-            String mn = this.name;
-
-            // special-case built-in class loaders to avoid URL connection
-            if (loader == null) {
-                return BootLoader.findResourceAsStream(mn, name);
-            } else if (loader instanceof BuiltinClassLoader) {
-                return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name);
+        if (isNamed() && !ResourceHelper.isSimpleResource(name)) {
+            Module caller = Reflection.getCallerClass().getModule();
+            if (caller != this && caller != Object.class.getModule()) {
+                // ignore packages added for proxies via addPackage
+                Set<String> packages = getDescriptor().packages();
+                String pn = ResourceHelper.getPackageName(name);
+                if (packages.contains(pn) && !isOpen(pn, caller)) {
+                    // resource is in package not open to caller
+                    return null;
+                }
             }
-
-            // use SharedSecrets to invoke protected method
-            url = SharedSecrets.getJavaLangAccess().findResource(loader, mn, name);
-
-        } else {
-
-            // unnamed module
-            if (loader == null) {
-                url = BootLoader.findResource(name);
-            } else {
-                return loader.getResourceAsStream(name);
-            }
-
         }
 
-        // fallthrough to URL case
+        String mn = this.name;
+
+        // special-case built-in class loaders to avoid URL connection
+        if (loader == null) {
+            return BootLoader.findResourceAsStream(mn, name);
+        } else if (loader instanceof BuiltinClassLoader) {
+            return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name);
+        }
+
+        // locate resource in module
+        JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
+        URL url = jla.findResource(loader, mn, name);
         if (url != null) {
             try {
                 return url.openStream();
@@ -1053,6 +1480,7 @@
 
     // JVM_DefineModule
     private static native void defineModule0(Module module,
+                                             boolean isOpen,
                                              String version,
                                              String location,
                                              String[] pns);
@@ -1098,15 +1526,31 @@
                 }
                 @Override
                 public void addExports(Module m, String pn, Module other) {
-                    m.implAddExports(pn, other, true);
+                    m.implAddExportsOrOpens(pn, other, false, true);
+                }
+                @Override
+                public void addOpens(Module m, String pn, Module other) {
+                    m.implAddExportsOrOpens(pn, other, true, true);
                 }
                 @Override
                 public void addExportsToAll(Module m, String pn) {
-                    m.implAddExports(pn, Module.EVERYONE_MODULE, true);
+                    m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true);
+                }
+                @Override
+                public void addOpensToAll(Module m, String pn) {
+                    m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, true, true);
                 }
                 @Override
                 public void addExportsToAllUnnamed(Module m, String pn) {
-                    m.implAddExports(pn, Module.ALL_UNNAMED_MODULE, true);
+                    m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true);
+                }
+                @Override
+                public void addOpensToAllUnnamed(Module m, String pn) {
+                    m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, true, true);
+                }
+                @Override
+                public void addUses(Module m, Class<?> service) {
+                    m.implAddUses(service);
                 }
                 @Override
                 public void addPackage(Module m, String pn) {
@@ -1116,6 +1560,14 @@
                 public ServicesCatalog getServicesCatalog(Layer layer) {
                     return layer.getServicesCatalog();
                 }
+                @Override
+                public Stream<Layer> layers(Layer layer) {
+                    return layer.layers();
+                }
+                @Override
+                public Stream<Layer> layers(ClassLoader loader) {
+                    return Layer.layers(loader);
+                }
             });
     }
 }
--- a/jdk/src/java.base/share/classes/java/net/Authenticator.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/net/Authenticator.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,8 @@
 
 package java.net;
 
+import sun.net.www.protocol.http.AuthenticatorKeys;
+
 /**
  * The class Authenticator represents an object that knows how to obtain
  * authentication for a network connection.  Usually, it will do this
@@ -70,6 +72,7 @@
     private String requestingScheme;
     private URL requestingURL;
     private RequestorType requestingAuthType;
+    private final String key = AuthenticatorKeys.computeKey(this);
 
     /**
      * The type of the entity requesting authentication.
@@ -349,6 +352,75 @@
     }
 
     /**
+     * Ask the given {@code authenticator} for a password. If the given
+     * {@code authenticator} is null, the authenticator, if any, that has been
+     * registered with the system using {@link #setDefault(java.net.Authenticator)
+     * setDefault} is used.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("requestPasswordAuthentication")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param authenticator the authenticator, or {@code null}.
+     * @param host The hostname of the site requesting authentication.
+     * @param addr The InetAddress of the site requesting authorization,
+     *             or null if not known.
+     * @param port the port for the requested connection
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user
+     * @param scheme The authentication scheme
+     * @param url The requesting URL that caused the authentication
+     * @param reqType The type (server or proxy) of the entity requesting
+     *              authentication.
+     *
+     * @return The username/password, or {@code null} if one can't be gotten.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        the password authentication request.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     *
+     * @since 9
+     */
+    public static PasswordAuthentication requestPasswordAuthentication(
+                                    Authenticator authenticator,
+                                    String host,
+                                    InetAddress addr,
+                                    int port,
+                                    String protocol,
+                                    String prompt,
+                                    String scheme,
+                                    URL url,
+                                    RequestorType reqType) {
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission requestPermission
+                = new NetPermission("requestPasswordAuthentication");
+            sm.checkPermission(requestPermission);
+        }
+
+        Authenticator a = authenticator == null ? theAuthenticator : authenticator;
+        if (a == null) {
+            return null;
+        } else {
+            return a.requestPasswordAuthenticationInstance(host,
+                                                           addr,
+                                                           port,
+                                                           protocol,
+                                                           prompt,
+                                                           scheme,
+                                                           url,
+                                                           reqType);
+        }
+    }
+
+    /**
      * Ask this authenticator for a password.
      *
      * @param host The hostname of the site requesting authentication.
@@ -493,4 +565,11 @@
     protected RequestorType getRequestorType () {
         return requestingAuthType;
     }
+
+    static String getKey(Authenticator a) {
+        return a.key;
+    }
+    static {
+        AuthenticatorKeys.setAuthenticatorKeyAccess(Authenticator::getKey);
+    }
 }
--- a/jdk/src/java.base/share/classes/java/net/HttpURLConnection.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/net/HttpURLConnection.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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
@@ -103,6 +103,53 @@
     protected long fixedContentLengthLong = -1;
 
     /**
+     * Supplies an {@link java.net.Authenticator Authenticator} to be used
+     * when authentication is requested through the HTTP protocol for
+     * this {@code HttpURLConnection}.
+     * If no authenticator is supplied, the
+     * {@linkplain Authenticator#setDefault(java.net.Authenticator) default
+     * authenticator} will be used.
+     *
+     * @implSpec The default behavior of this method is to unconditionally
+     *           throw {@link UnsupportedOperationException}. Concrete
+     *           implementations of {@code HttpURLConnection}
+     *           which support supplying an {@code Authenticator} for a
+     *           specific {@code HttpURLConnection} instance should
+     *           override this method to implement a different behavior.
+     *
+     * @implNote Depending on authentication schemes, an implementation
+     *           may or may not need to use the provided authenticator
+     *           to obtain a password. For instance, an implementation that
+     *           relies on third-party security libraries may still invoke the
+     *           default authenticator if these libraries are configured
+     *           to do so.
+     *           Likewise, an implementation that supports transparent
+     *           NTLM authentication may let the system attempt
+     *           to connect using the system user credentials first,
+     *           before invoking the provided authenticator.
+     *           <br>
+     *           However, if an authenticator is specifically provided,
+     *           then the underlying connection may only be reused for
+     *           {@code HttpURLConnection} instances which share the same
+     *           {@code Authenticator} instance, and authentication information,
+     *           if cached, may only be reused for an {@code HttpURLConnection}
+     *           sharing that same {@code Authenticator}.
+     *
+     * @param auth The {@code Authenticator} that should be used by this
+     *           {@code HttpURLConnection}.
+     *
+     * @throws  UnsupportedOperationException if setting an Authenticator is
+     *          not supported by the underlying implementation.
+     * @throws  IllegalStateException if URLConnection is already connected.
+     * @throws  NullPointerException if the supplied {@code auth} is {@code null}.
+     * @since 9
+     */
+    public void setAuthenticator(Authenticator auth) {
+        throw new UnsupportedOperationException("Supplying an authenticator"
+                    + " is not supported by " + this.getClass());
+    }
+
+    /**
      * Returns the key for the {@code n}<sup>th</sup> header field.
      * Some implementations may treat the {@code 0}<sup>th</sup>
      * header field as special, i.e. as the status line returned by the HTTP
--- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -72,6 +72,10 @@
  * <p>
  * The classes that are loaded are by default granted permission only to
  * access the URLs specified when the URLClassLoader was created.
+ * <p>
+ * This class loader supports the loading of classes from the contents of a
+ * <a href="../util/jar/JarFile.html#multirelease">multi-release</a> JAR file
+ * that is referred to by a given URL.
  *
  * @author  David Connelly
  * @since   1.2
--- a/jdk/src/java.base/share/classes/java/time/chrono/Chronology.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/time/chrono/Chronology.java	Wed Jul 05 22:32:06 2017 +0200
@@ -151,7 +151,7 @@
  * Each chronology must define a chronology ID that is unique within the system.
  * If the chronology represents a calendar system defined by the
  * CLDR specification then the calendar type is the concatenation of the
- * CLDR type and, if applicable, the CLDR variant,
+ * CLDR type and, if applicable, the CLDR variant.
  *
  * @implSpec
  * This interface must be implemented with care to ensure other classes operate correctly.
@@ -177,7 +177,7 @@
      *
      * @param temporal  the temporal to convert, not null
      * @return the chronology, not null
-     * @throws DateTimeException if unable to convert to an {@code Chronology}
+     * @throws DateTimeException if unable to convert to a {@code Chronology}
      */
     static Chronology from(TemporalAccessor temporal) {
         Objects.requireNonNull(temporal, "temporal");
@@ -203,7 +203,7 @@
      * For example, the locale "en-JP-u-ca-japanese" represents the English
      * language as used in Japan with the Japanese calendar system.
      * <p>
-     * This method finds the desired calendar system by in a manner equivalent
+     * This method finds the desired calendar system in a manner equivalent
      * to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}.
      * If the "ca" key is not present, then {@code IsoChronology} is returned.
      * <p>
@@ -286,7 +286,7 @@
      * <p>
      * The calendar type is an identifier defined by the CLDR and
      * <em>Unicode Locale Data Markup Language (LDML)</em> specifications
-     * to uniquely identification a calendar.
+     * to uniquely identify a calendar.
      * The {@code getCalendarType} is the concatenation of the CLDR calendar type
      * and the variant, if applicable, is appended separated by "-".
      * The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}.
--- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java	Wed Jul 05 22:32:06 2017 +0200
@@ -119,6 +119,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import sun.text.spi.JavaTimeDateTimePatternProvider;
 import sun.util.locale.provider.LocaleProviderAdapter;
 import sun.util.locale.provider.LocaleResources;
 import sun.util.locale.provider.TimeZoneNameUtility;
@@ -212,9 +213,10 @@
         if (dateStyle == null && timeStyle == null) {
             throw new IllegalArgumentException("Either dateStyle or timeStyle must be non-null");
         }
-        LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale);
-        String pattern = lr.getJavaTimeDateTimePattern(
-                convertStyle(timeStyle), convertStyle(dateStyle), chrono.getCalendarType());
+        LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(JavaTimeDateTimePatternProvider.class, locale);
+        JavaTimeDateTimePatternProvider provider = adapter.getJavaTimeDateTimePatternProvider();
+        String pattern = provider.getJavaTimeDateTimePattern(convertStyle(timeStyle),
+                         convertStyle(dateStyle), chrono.getCalendarType(), locale);
         return pattern;
     }
 
--- a/jdk/src/java.base/share/classes/java/util/ArrayDeque.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/ArrayDeque.java	Wed Jul 05 22:32:06 2017 +0200
@@ -36,6 +36,8 @@
 
 import java.io.Serializable;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
 
 /**
  * Resizable-array implementation of the {@link Deque} interface.  Array
@@ -87,81 +89,89 @@
 public class ArrayDeque<E> extends AbstractCollection<E>
                            implements Deque<E>, Cloneable, Serializable
 {
+    /*
+     * VMs excel at optimizing simple array loops where indices are
+     * incrementing or decrementing over a valid slice, e.g.
+     *
+     * for (int i = start; i < end; i++) ... elements[i]
+     *
+     * Because in a circular array, elements are in general stored in
+     * two disjoint such slices, we help the VM by writing unusual
+     * nested loops for all traversals over the elements.  Having only
+     * one hot inner loop body instead of two or three eases human
+     * maintenance and encourages VM loop inlining into the caller.
+     */
+
     /**
      * The array in which the elements of the deque are stored.
-     * The capacity of the deque is the length of this array, which is
-     * always a power of two. The array is never allowed to become
-     * full, except transiently within an addX method where it is
-     * resized (see doubleCapacity) immediately upon becoming full,
-     * thus avoiding head and tail wrapping around to equal each
-     * other.  We also guarantee that all array cells not holding
-     * deque elements are always null.
+     * All array cells not holding deque elements are always null.
+     * The array always has at least one null slot (at tail).
      */
-    transient Object[] elements; // non-private to simplify nested class access
+    transient Object[] elements;
 
     /**
      * The index of the element at the head of the deque (which is the
      * element that would be removed by remove() or pop()); or an
-     * arbitrary number equal to tail if the deque is empty.
+     * arbitrary number 0 <= head < elements.length equal to tail if
+     * the deque is empty.
      */
     transient int head;
 
     /**
      * The index at which the next element would be added to the tail
-     * of the deque (via addLast(E), add(E), or push(E)).
+     * of the deque (via addLast(E), add(E), or push(E));
+     * elements[tail] is always null.
      */
     transient int tail;
 
     /**
-     * The minimum capacity that we'll use for a newly created deque.
-     * Must be a power of 2.
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
      */
-    private static final int MIN_INITIAL_CAPACITY = 8;
-
-    // ******  Array allocation and resizing utilities ******
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 
     /**
-     * Allocates empty array to hold the given number of elements.
+     * Increases the capacity of this deque by at least the given amount.
      *
-     * @param numElements  the number of elements to hold
+     * @param needed the required minimum extra capacity; must be positive
      */
-    private void allocateElements(int numElements) {
-        int initialCapacity = MIN_INITIAL_CAPACITY;
-        // Find the best power of two to hold elements.
-        // Tests "<=" because arrays aren't kept full.
-        if (numElements >= initialCapacity) {
-            initialCapacity = numElements;
-            initialCapacity |= (initialCapacity >>>  1);
-            initialCapacity |= (initialCapacity >>>  2);
-            initialCapacity |= (initialCapacity >>>  4);
-            initialCapacity |= (initialCapacity >>>  8);
-            initialCapacity |= (initialCapacity >>> 16);
-            initialCapacity++;
-
-            if (initialCapacity < 0)    // Too many elements, must back off
-                initialCapacity >>>= 1; // Good luck allocating 2^30 elements
+    private void grow(int needed) {
+        // overflow-conscious code
+        final int oldCapacity = elements.length;
+        int newCapacity;
+        // Double capacity if small; else grow by 50%
+        int jump = (oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1);
+        if (jump < needed
+            || (newCapacity = (oldCapacity + jump)) - MAX_ARRAY_SIZE > 0)
+            newCapacity = newCapacity(needed, jump);
+        elements = Arrays.copyOf(elements, newCapacity);
+        // Exceptionally, here tail == head needs to be disambiguated
+        if (tail < head || (tail == head && elements[head] != null)) {
+            // wrap around; slide first leg forward to end of array
+            int newSpace = newCapacity - oldCapacity;
+            System.arraycopy(elements, head,
+                             elements, head + newSpace,
+                             oldCapacity - head);
+            Arrays.fill(elements, head, head + newSpace, null);
+            head += newSpace;
         }
-        elements = new Object[initialCapacity];
     }
 
-    /**
-     * Doubles the capacity of this deque.  Call only when full, i.e.,
-     * when head and tail have wrapped around to become equal.
-     */
-    private void doubleCapacity() {
-        assert head == tail;
-        int p = head;
-        int n = elements.length;
-        int r = n - p; // number of elements to the right of p
-        int newCapacity = n << 1;
-        if (newCapacity < 0)
-            throw new IllegalStateException("Sorry, deque too big");
-        Object[] a = new Object[newCapacity];
-        System.arraycopy(elements, p, a, 0, r);
-        System.arraycopy(elements, 0, a, r, p);
-        elements = a;
-        head = 0;
-        tail = n;
+    /** Capacity calculation for edge conditions, especially overflow. */
+    private int newCapacity(int needed, int jump) {
+        final int oldCapacity = elements.length, minCapacity;
+        if ((minCapacity = oldCapacity + needed) - MAX_ARRAY_SIZE > 0) {
+            if (minCapacity < 0)
+                throw new IllegalStateException("Sorry, deque too big");
+            return Integer.MAX_VALUE;
+        }
+        if (needed > jump)
+            return minCapacity;
+        return (oldCapacity + jump - MAX_ARRAY_SIZE < 0)
+            ? oldCapacity + jump
+            : MAX_ARRAY_SIZE;
     }
 
     /**
@@ -176,10 +186,13 @@
      * Constructs an empty array deque with an initial capacity
      * sufficient to hold the specified number of elements.
      *
-     * @param numElements  lower bound on initial capacity of the deque
+     * @param numElements lower bound on initial capacity of the deque
      */
     public ArrayDeque(int numElements) {
-        allocateElements(numElements);
+        elements =
+            new Object[(numElements < 1) ? 1 :
+                       (numElements == Integer.MAX_VALUE) ? Integer.MAX_VALUE :
+                       numElements + 1];
     }
 
     /**
@@ -193,10 +206,71 @@
      * @throws NullPointerException if the specified collection is null
      */
     public ArrayDeque(Collection<? extends E> c) {
-        allocateElements(c.size());
+        this(c.size());
         addAll(c);
     }
 
+    /**
+     * Increments i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int inc(int i, int modulus) {
+        if (++i >= modulus) i = 0;
+        return i;
+    }
+
+    /**
+     * Decrements i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int dec(int i, int modulus) {
+        if (--i < 0) i = modulus - 1;
+        return i;
+    }
+
+    /**
+     * Circularly adds the given distance to index i, mod modulus.
+     * Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
+     * @return index 0 <= i < modulus
+     */
+    static final int add(int i, int distance, int modulus) {
+        if ((i += distance) - modulus >= 0) i -= modulus;
+        return i;
+    }
+
+    /**
+     * Subtracts j from i, mod modulus.
+     * Index i must be logically ahead of index j.
+     * Precondition: 0 <= i < modulus, 0 <= j < modulus.
+     * @return the "circular distance" from j to i; corner case i == j
+     * is diambiguated to "empty", returning 0.
+     */
+    static final int sub(int i, int j, int modulus) {
+        if ((i -= j) < 0) i += modulus;
+        return i;
+    }
+
+    /**
+     * Returns element at array index i.
+     * This is a slight abuse of generics, accepted by javac.
+     */
+    @SuppressWarnings("unchecked")
+    static final <E> E elementAt(Object[] es, int i) {
+        return (E) es[i];
+    }
+
+    /**
+     * A version of elementAt that checks for null elements.
+     * This check doesn't catch all possible comodifications,
+     * but does catch ones that corrupt traversal.
+     */
+    static final <E> E nonNullElementAt(Object[] es, int i) {
+        @SuppressWarnings("unchecked") E e = (E) es[i];
+        if (e == null)
+            throw new ConcurrentModificationException();
+        return e;
+    }
+
     // The main insertion and extraction methods are addFirst,
     // addLast, pollFirst, pollLast. The other methods are defined in
     // terms of these.
@@ -210,9 +284,10 @@
     public void addFirst(E e) {
         if (e == null)
             throw new NullPointerException();
-        elements[head = (head - 1) & (elements.length - 1)] = e;
+        final Object[] es = elements;
+        es[head = dec(head, es.length)] = e;
         if (head == tail)
-            doubleCapacity();
+            grow(1);
     }
 
     /**
@@ -226,9 +301,29 @@
     public void addLast(E e) {
         if (e == null)
             throw new NullPointerException();
-        elements[tail] = e;
-        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
-            doubleCapacity();
+        final Object[] es = elements;
+        es[tail] = e;
+        if (head == (tail = inc(tail, es.length)))
+            grow(1);
+    }
+
+    /**
+     * Adds all of the elements in the specified collection at the end
+     * of this deque, as if by calling {@link #addLast} on each one,
+     * in the order that they are returned by the collection's
+     * iterator.
+     *
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        final int s, needed;
+        if ((needed = (s = size()) + c.size() + 1 - elements.length) > 0)
+            grow(needed);
+        c.forEach(this::addLast);
+        return size() > s;
     }
 
     /**
@@ -259,78 +354,70 @@
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E removeFirst() {
-        E x = pollFirst();
-        if (x == null)
+        E e = pollFirst();
+        if (e == null)
             throw new NoSuchElementException();
-        return x;
+        return e;
     }
 
     /**
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E removeLast() {
-        E x = pollLast();
-        if (x == null)
+        E e = pollLast();
+        if (e == null)
             throw new NoSuchElementException();
-        return x;
+        return e;
     }
 
     public E pollFirst() {
-        final Object[] elements = this.elements;
-        final int h = head;
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[h];
-        // Element is null if deque empty
-        if (result != null) {
-            elements[h] = null; // Must null out slot
-            head = (h + 1) & (elements.length - 1);
+        final Object[] es;
+        final int h;
+        E e = elementAt(es = elements, h = head);
+        if (e != null) {
+            es[h] = null;
+            head = inc(h, es.length);
         }
-        return result;
+        return e;
     }
 
     public E pollLast() {
-        final Object[] elements = this.elements;
-        final int t = (tail - 1) & (elements.length - 1);
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[t];
-        if (result != null) {
-            elements[t] = null;
-            tail = t;
-        }
-        return result;
+        final Object[] es;
+        final int t;
+        E e = elementAt(es = elements, t = dec(tail, es.length));
+        if (e != null)
+            es[tail = t] = null;
+        return e;
     }
 
     /**
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E getFirst() {
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[head];
-        if (result == null)
+        E e = elementAt(elements, head);
+        if (e == null)
             throw new NoSuchElementException();
-        return result;
+        return e;
     }
 
     /**
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E getLast() {
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[(tail - 1) & (elements.length - 1)];
-        if (result == null)
+        final Object[] es = elements;
+        E e = elementAt(es, dec(tail, es.length));
+        if (e == null)
             throw new NoSuchElementException();
-        return result;
+        return e;
     }
 
-    @SuppressWarnings("unchecked")
     public E peekFirst() {
-        // elements[head] is null if deque empty
-        return (E) elements[head];
+        return elementAt(elements, head);
     }
 
-    @SuppressWarnings("unchecked")
     public E peekLast() {
-        return (E) elements[(tail - 1) & (elements.length - 1)];
+        final Object[] es;
+        return elementAt(es = elements, dec(tail, es.length));
     }
 
     /**
@@ -347,13 +434,15 @@
      */
     public boolean removeFirstOccurrence(Object o) {
         if (o != null) {
-            int mask = elements.length - 1;
-            int i = head;
-            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
-                if (o.equals(x)) {
-                    delete(i);
-                    return true;
-                }
+            final Object[] es = elements;
+            for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    if (o.equals(es[i])) {
+                        delete(i);
+                        return true;
+                    }
+                if (to == end) break;
             }
         }
         return false;
@@ -373,13 +462,15 @@
      */
     public boolean removeLastOccurrence(Object o) {
         if (o != null) {
-            int mask = elements.length - 1;
-            int i = (tail - 1) & mask;
-            for (Object x; (x = elements[i]) != null; i = (i - 1) & mask) {
-                if (o.equals(x)) {
-                    delete(i);
-                    return true;
-                }
+            final Object[] es = elements;
+            for (int i = tail, end = head, to = (i >= end) ? end : 0;
+                 ; i = es.length, to = end) {
+                for (i--; i > to - 1; i--)
+                    if (o.equals(es[i])) {
+                        delete(i);
+                        return true;
+                    }
+                if (to == end) break;
             }
         }
         return false;
@@ -499,59 +590,47 @@
         return removeFirst();
     }
 
-    private void checkInvariants() {
-        assert elements[tail] == null;
-        assert head == tail ? elements[head] == null :
-            (elements[head] != null &&
-             elements[(tail - 1) & (elements.length - 1)] != null);
-        assert elements[(head - 1) & (elements.length - 1)] == null;
-    }
-
     /**
-     * Removes the element at the specified position in the elements array,
-     * adjusting head and tail as necessary.  This can result in motion of
-     * elements backwards or forwards in the array.
+     * Removes the element at the specified position in the elements array.
+     * This can result in forward or backwards motion of array elements.
+     * We optimize for least element motion.
      *
      * <p>This method is called delete rather than remove to emphasize
      * that its semantics differ from those of {@link List#remove(int)}.
      *
-     * @return true if elements moved backwards
+     * @return true if elements near tail moved backwards
      */
     boolean delete(int i) {
-        checkInvariants();
-        final Object[] elements = this.elements;
-        final int mask = elements.length - 1;
-        final int h = head;
-        final int t = tail;
-        final int front = (i - h) & mask;
-        final int back  = (t - i) & mask;
-
-        // Invariant: head <= i < tail mod circularity
-        if (front >= ((t - h) & mask))
-            throw new ConcurrentModificationException();
-
-        // Optimize for least element motion
+        final Object[] es = elements;
+        final int capacity = es.length;
+        final int h, t;
+        // number of elements before to-be-deleted elt
+        final int front = sub(i, h = head, capacity);
+        // number of elements after to-be-deleted elt
+        final int back = sub(t = tail, i, capacity) - 1;
         if (front < back) {
+            // move front elements forwards
             if (h <= i) {
-                System.arraycopy(elements, h, elements, h + 1, front);
+                System.arraycopy(es, h, es, h + 1, front);
             } else { // Wrap around
-                System.arraycopy(elements, 0, elements, 1, i);
-                elements[0] = elements[mask];
-                System.arraycopy(elements, h, elements, h + 1, mask - h);
+                System.arraycopy(es, 0, es, 1, i);
+                es[0] = es[capacity - 1];
+                System.arraycopy(es, h, es, h + 1, front - (i + 1));
             }
-            elements[h] = null;
-            head = (h + 1) & mask;
+            es[h] = null;
+            head = inc(h, capacity);
             return false;
         } else {
-            if (i < t) { // Copy the null tail as well
-                System.arraycopy(elements, i + 1, elements, i, back);
-                tail = t - 1;
+            // move back elements backwards
+            tail = dec(t, capacity);
+            if (i <= tail) {
+                System.arraycopy(es, i + 1, es, i, back);
             } else { // Wrap around
-                System.arraycopy(elements, i + 1, elements, i, mask - i);
-                elements[mask] = elements[0];
-                System.arraycopy(elements, 1, elements, 0, t);
-                tail = (t - 1) & mask;
+                System.arraycopy(es, i + 1, es, i, capacity - (i + 1));
+                es[capacity - 1] = es[0];
+                System.arraycopy(es, 1, es, 0, t - 1);
             }
+            es[tail] = null;
             return true;
         }
     }
@@ -564,7 +643,7 @@
      * @return the number of elements in this deque
      */
     public int size() {
-        return (tail - head) & (elements.length - 1);
+        return sub(tail, head, elements.length);
     }
 
     /**
@@ -593,101 +672,317 @@
     }
 
     private class DeqIterator implements Iterator<E> {
-        /**
-         * Index of element to be returned by subsequent call to next.
-         */
-        private int cursor = head;
+        /** Index of element to be returned by subsequent call to next. */
+        int cursor;
 
-        /**
-         * Tail recorded at construction (also in remove), to stop
-         * iterator and also to check for comodification.
-         */
-        private int fence = tail;
+        /** Number of elements yet to be returned. */
+        int remaining = size();
 
         /**
          * Index of element returned by most recent call to next.
          * Reset to -1 if element is deleted by a call to remove.
          */
-        private int lastRet = -1;
+        int lastRet = -1;
 
-        public boolean hasNext() {
-            return cursor != fence;
+        DeqIterator() { cursor = head; }
+
+        public final boolean hasNext() {
+            return remaining > 0;
         }
 
         public E next() {
-            if (cursor == fence)
+            if (remaining <= 0)
                 throw new NoSuchElementException();
-            @SuppressWarnings("unchecked")
-            E result = (E) elements[cursor];
-            // This check doesn't catch all possible comodifications,
-            // but does catch the ones that corrupt traversal
-            if (tail != fence || result == null)
-                throw new ConcurrentModificationException();
-            lastRet = cursor;
-            cursor = (cursor + 1) & (elements.length - 1);
-            return result;
+            final Object[] es = elements;
+            E e = nonNullElementAt(es, cursor);
+            cursor = inc(lastRet = cursor, es.length);
+            remaining--;
+            return e;
         }
 
-        public void remove() {
+        void postDelete(boolean leftShifted) {
+            if (leftShifted)
+                cursor = dec(cursor, elements.length);
+        }
+
+        public final void remove() {
             if (lastRet < 0)
                 throw new IllegalStateException();
-            if (delete(lastRet)) { // if left-shifted, undo increment in next()
-                cursor = (cursor - 1) & (elements.length - 1);
-                fence = tail;
-            }
+            postDelete(delete(lastRet));
             lastRet = -1;
         }
 
         public void forEachRemaining(Consumer<? super E> action) {
             Objects.requireNonNull(action);
-            Object[] a = elements;
-            int m = a.length - 1, f = fence, i = cursor;
-            cursor = f;
-            while (i != f) {
-                @SuppressWarnings("unchecked") E e = (E)a[i];
-                i = (i + 1) & m;
-                if (e == null)
-                    throw new ConcurrentModificationException();
-                action.accept(e);
+            int r;
+            if ((r = remaining) <= 0)
+                return;
+            remaining = 0;
+            final Object[] es = elements;
+            if (es[cursor] == null || sub(tail, cursor, es.length) != r)
+                throw new ConcurrentModificationException();
+            for (int i = cursor, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    action.accept(elementAt(es, i));
+                if (to == end) {
+                    if (end != tail)
+                        throw new ConcurrentModificationException();
+                    lastRet = dec(end, es.length);
+                    break;
+                }
+            }
+        }
+    }
+
+    private class DescendingIterator extends DeqIterator {
+        DescendingIterator() { cursor = dec(tail, elements.length); }
+
+        public final E next() {
+            if (remaining <= 0)
+                throw new NoSuchElementException();
+            final Object[] es = elements;
+            E e = nonNullElementAt(es, cursor);
+            cursor = dec(lastRet = cursor, es.length);
+            remaining--;
+            return e;
+        }
+
+        void postDelete(boolean leftShifted) {
+            if (!leftShifted)
+                cursor = inc(cursor, elements.length);
+        }
+
+        public final void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            int r;
+            if ((r = remaining) <= 0)
+                return;
+            remaining = 0;
+            final Object[] es = elements;
+            if (es[cursor] == null || sub(cursor, head, es.length) + 1 != r)
+                throw new ConcurrentModificationException();
+            for (int i = cursor, end = head, to = (i >= end) ? end : 0;
+                 ; i = es.length - 1, to = end) {
+                // hotspot generates faster code than for: i >= to !
+                for (; i > to - 1; i--)
+                    action.accept(elementAt(es, i));
+                if (to == end) {
+                    if (end != head)
+                        throw new ConcurrentModificationException();
+                    lastRet = end;
+                    break;
+                }
             }
         }
     }
 
     /**
-     * This class is nearly a mirror-image of DeqIterator, using tail
-     * instead of head for initial cursor, and head instead of tail
-     * for fence.
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * deque.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#NONNULL}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
      */
-    private class DescendingIterator implements Iterator<E> {
-        private int cursor = tail;
-        private int fence = head;
-        private int lastRet = -1;
+    public Spliterator<E> spliterator() {
+        return new DeqSpliterator();
+    }
+
+    final class DeqSpliterator implements Spliterator<E> {
+        private int fence;      // -1 until first use
+        private int cursor;     // current index, modified on traverse/split
+
+        /** Constructs late-binding spliterator over all elements. */
+        DeqSpliterator() {
+            this.fence = -1;
+        }
+
+        /** Constructs spliterator over the given range. */
+        DeqSpliterator(int origin, int fence) {
+            // assert 0 <= origin && origin < elements.length;
+            // assert 0 <= fence && fence < elements.length;
+            this.cursor = origin;
+            this.fence = fence;
+        }
+
+        /** Ensures late-binding initialization; then returns fence. */
+        private int getFence() { // force initialization
+            int t;
+            if ((t = fence) < 0) {
+                t = fence = tail;
+                cursor = head;
+            }
+            return t;
+        }
 
-        public boolean hasNext() {
-            return cursor != fence;
+        public DeqSpliterator trySplit() {
+            final Object[] es = elements;
+            final int i, n;
+            return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
+                ? null
+                : new DeqSpliterator(i, cursor = add(i, n, es.length));
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            final int end = getFence(), cursor = this.cursor;
+            final Object[] es = elements;
+            if (cursor != end) {
+                this.cursor = end;
+                // null check at both ends of range is sufficient
+                if (es[cursor] == null || es[dec(end, es.length)] == null)
+                    throw new ConcurrentModificationException();
+                for (int i = cursor, to = (i <= end) ? end : es.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(elementAt(es, i));
+                    if (to == end) break;
+                }
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final Object[] es = elements;
+            if (fence < 0) { fence = tail; cursor = head; } // late-binding
+            final int i;
+            if ((i = cursor) == fence)
+                return false;
+            E e = nonNullElementAt(es, i);
+            cursor = inc(i, es.length);
+            action.accept(e);
+            return true;
+        }
+
+        public long estimateSize() {
+            return sub(getFence(), cursor, elements.length);
         }
 
-        public E next() {
-            if (cursor == fence)
-                throw new NoSuchElementException();
-            cursor = (cursor - 1) & (elements.length - 1);
-            @SuppressWarnings("unchecked")
-            E result = (E) elements[cursor];
-            if (head != fence || result == null)
-                throw new ConcurrentModificationException();
-            lastRet = cursor;
-            return result;
+        public int characteristics() {
+            return Spliterator.NONNULL
+                | Spliterator.ORDERED
+                | Spliterator.SIZED
+                | Spliterator.SUBSIZED;
+        }
+    }
+
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final Object[] es = elements;
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                action.accept(elementAt(es, i));
+            if (to == end) {
+                if (end != tail) throw new ConcurrentModificationException();
+                break;
+            }
         }
+    }
 
-        public void remove() {
-            if (lastRet < 0)
-                throw new IllegalStateException();
-            if (!delete(lastRet)) {
-                cursor = (cursor + 1) & (elements.length - 1);
-                fence = head;
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final Object[] es = elements;
+        // Optimize for initial run of survivors
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                if (filter.test(elementAt(es, i)))
+                    return bulkRemoveModified(filter, i);
+            if (to == end) {
+                if (end != tail) throw new ConcurrentModificationException();
+                break;
             }
-            lastRet = -1;
         }
+        return false;
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /**
+     * Helper for bulkRemove, in case of at least one deletion.
+     * Tolerate predicates that reentrantly access the collection for
+     * read (but writers still get CME), so traverse once to find
+     * elements to delete, a second pass to physically expunge.
+     *
+     * @param beg valid index of first element to be deleted
+     */
+    private boolean bulkRemoveModified(
+        Predicate<? super E> filter, final int beg) {
+        final Object[] es = elements;
+        final int capacity = es.length;
+        final int end = tail;
+        final long[] deathRow = nBits(sub(end, beg, capacity));
+        deathRow[0] = 1L;   // set bit 0
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; i = 0, to = end, k -= capacity) {
+            for (; i < to; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - k);
+            if (to == end) break;
+        }
+        // a two-finger traversal, with hare i reading, tortoise w writing
+        int w = beg;
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; w = 0) { // w rejoins i on second leg
+            // In this loop, i and w are on the same leg, with i > w
+            for (; i < to; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (to == end) break;
+            // In this loop, w is on the first leg, i on the second
+            for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (i >= to) {
+                if (w == capacity) w = 0; // "corner" case
+                break;
+            }
+        }
+        if (end != tail) throw new ConcurrentModificationException();
+        circularClear(es, tail = w, end);
+        return true;
     }
 
     /**
@@ -700,11 +995,13 @@
      */
     public boolean contains(Object o) {
         if (o != null) {
-            int mask = elements.length - 1;
-            int i = head;
-            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
-                if (o.equals(x))
-                    return true;
+            final Object[] es = elements;
+            for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    if (o.equals(es[i]))
+                        return true;
+                if (to == end) break;
             }
         }
         return false;
@@ -732,16 +1029,18 @@
      * The deque will be empty after this call returns.
      */
     public void clear() {
-        int h = head;
-        int t = tail;
-        if (h != t) { // clear all cells
-            head = tail = 0;
-            int i = h;
-            int mask = elements.length - 1;
-            do {
-                elements[i] = null;
-                i = (i + 1) & mask;
-            } while (i != t);
+        circularClear(elements, head, tail);
+        head = tail = 0;
+    }
+
+    /**
+     * Nulls out slots starting at array index i, upto index end.
+     */
+    private static void circularClear(Object[] es, int i, int end) {
+        for (int to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            Arrays.fill(es, i, to, null);
+            if (to == end) break;
         }
     }
 
@@ -759,13 +1058,23 @@
      * @return an array containing all of the elements in this deque
      */
     public Object[] toArray() {
-        final int head = this.head;
-        final int tail = this.tail;
-        boolean wrap = (tail < head);
-        int end = wrap ? tail + elements.length : tail;
-        Object[] a = Arrays.copyOfRange(elements, head, end);
-        if (wrap)
-            System.arraycopy(elements, 0, a, elements.length - head, tail);
+        return toArray(Object[].class);
+    }
+
+    private <T> T[] toArray(Class<T[]> klazz) {
+        final Object[] es = elements;
+        final T[] a;
+        final int head = this.head, tail = this.tail, end;
+        if ((end = tail + ((head <= tail) ? 0 : es.length)) >= 0) {
+            // Uses null extension feature of copyOfRange
+            a = Arrays.copyOfRange(es, head, end, klazz);
+        } else {
+            // integer overflow!
+            a = Arrays.copyOfRange(es, 0, end - head, klazz);
+            System.arraycopy(es, head, a, 0, es.length - head);
+        }
+        if (end != tail)
+            System.arraycopy(es, 0, a, es.length - head, tail);
         return a;
     }
 
@@ -807,22 +1116,17 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        final int head = this.head;
-        final int tail = this.tail;
-        boolean wrap = (tail < head);
-        int size = (tail - head) + (wrap ? elements.length : 0);
-        int firstLeg = size - (wrap ? tail : 0);
-        int len = a.length;
-        if (size > len) {
-            a = (T[]) Arrays.copyOfRange(elements, head, head + size,
-                                         a.getClass());
-        } else {
-            System.arraycopy(elements, head, a, 0, firstLeg);
-            if (size < len)
-                a[size] = null;
+        final int size;
+        if ((size = size()) > a.length)
+            return toArray((Class<T[]>) a.getClass());
+        final Object[] es = elements;
+        for (int i = head, j = 0, len = Math.min(size, es.length - i);
+             ; i = 0, len = tail) {
+            System.arraycopy(es, i, a, j, len);
+            if ((j += len) == size) break;
         }
-        if (wrap)
-            System.arraycopy(elements, 0, a, firstLeg, tail);
+        if (size < a.length)
+            a[size] = null;
         return a;
     }
 
@@ -863,9 +1167,13 @@
         s.writeInt(size());
 
         // Write out elements in order.
-        int mask = elements.length - 1;
-        for (int i = head; i != tail; i = (i + 1) & mask)
-            s.writeObject(elements[i]);
+        final Object[] es = elements;
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                s.writeObject(es[i]);
+            if (to == end) break;
+        }
     }
 
     /**
@@ -881,106 +1189,33 @@
 
         // Read in size and allocate array
         int size = s.readInt();
-        allocateElements(size);
-        head = 0;
-        tail = size;
+        elements = new Object[size + 1];
+        this.tail = size;
 
         // Read in all elements in the proper order.
         for (int i = 0; i < size; i++)
             elements[i] = s.readObject();
     }
 
-    /**
-     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
-     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
-     * deque.
-     *
-     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
-     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
-     * {@link Spliterator#NONNULL}.  Overriding implementations should document
-     * the reporting of additional characteristic values.
-     *
-     * @return a {@code Spliterator} over the elements in this deque
-     * @since 1.8
-     */
-    public Spliterator<E> spliterator() {
-        return new DeqSpliterator<>(this, -1, -1);
-    }
-
-    static final class DeqSpliterator<E> implements Spliterator<E> {
-        private final ArrayDeque<E> deq;
-        private int fence;  // -1 until first use
-        private int index;  // current index, modified on traverse/split
-
-        /** Creates new spliterator covering the given array and range. */
-        DeqSpliterator(ArrayDeque<E> deq, int origin, int fence) {
-            this.deq = deq;
-            this.index = origin;
-            this.fence = fence;
-        }
-
-        private int getFence() { // force initialization
-            int t;
-            if ((t = fence) < 0) {
-                t = fence = deq.tail;
-                index = deq.head;
-            }
-            return t;
-        }
-
-        public DeqSpliterator<E> trySplit() {
-            int t = getFence(), h = index, n = deq.elements.length;
-            if (h != t && ((h + 1) & (n - 1)) != t) {
-                if (h > t)
-                    t += n;
-                int m = ((h + t) >>> 1) & (n - 1);
-                return new DeqSpliterator<E>(deq, h, index = m);
-            }
-            return null;
-        }
-
-        public void forEachRemaining(Consumer<? super E> consumer) {
-            if (consumer == null)
-                throw new NullPointerException();
-            Object[] a = deq.elements;
-            int m = a.length - 1, f = getFence(), i = index;
-            index = f;
-            while (i != f) {
-                @SuppressWarnings("unchecked") E e = (E)a[i];
-                i = (i + 1) & m;
-                if (e == null)
-                    throw new ConcurrentModificationException();
-                consumer.accept(e);
-            }
-        }
-
-        public boolean tryAdvance(Consumer<? super E> consumer) {
-            if (consumer == null)
-                throw new NullPointerException();
-            Object[] a = deq.elements;
-            int m = a.length - 1, f = getFence(), i = index;
-            if (i != f) {
-                @SuppressWarnings("unchecked") E e = (E)a[i];
-                index = (i + 1) & m;
-                if (e == null)
-                    throw new ConcurrentModificationException();
-                consumer.accept(e);
-                return true;
-            }
-            return false;
-        }
-
-        public long estimateSize() {
-            int n = getFence() - index;
-            if (n < 0)
-                n += deq.elements.length;
-            return (long) n;
-        }
-
-        @Override
-        public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.SIZED |
-                Spliterator.NONNULL | Spliterator.SUBSIZED;
+    /** debugging */
+    void checkInvariants() {
+        // Use head and tail fields with empty slot at tail strategy.
+        // head == tail disambiguates to "empty".
+        try {
+            int capacity = elements.length;
+            // assert 0 <= head && head < capacity;
+            // assert 0 <= tail && tail < capacity;
+            // assert capacity > 0;
+            // assert size() < capacity;
+            // assert head == tail || elements[head] != null;
+            // assert elements[tail] == null;
+            // assert head == tail || elements[dec(tail, capacity)] != null;
+        } catch (Throwable t) {
+            System.err.printf("head=%d tail=%d capacity=%d%n",
+                              head, tail, elements.length);
+            System.err.printf("elements=%s%n",
+                              Arrays.toString(elements));
+            throw t;
         }
     }
 
--- a/jdk/src/java.base/share/classes/java/util/ArrayList.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java	Wed Jul 05 22:32:06 2017 +0200
@@ -104,7 +104,6 @@
  * @see     Vector
  * @since   1.2
  */
-
 public class ArrayList<E> extends AbstractList<E>
         implements List<E>, RandomAccess, Cloneable, java.io.Serializable
 {
@@ -424,6 +423,11 @@
         return (E) elementData[index];
     }
 
+    @SuppressWarnings("unchecked")
+    static <E> E elementAt(Object[] es, int index) {
+        return (E) es[index];
+    }
+
     /**
      * Returns the element at the specified position in this list.
      *
@@ -553,7 +557,7 @@
         return false;
     }
 
-    /*
+    /**
      * Private remove method that skips bounds checking and does not
      * return the value removed.
      */
@@ -572,11 +576,7 @@
      */
     public void clear() {
         modCount++;
-
-        // clear to let GC do its work
-        for (int i = 0; i < size; i++)
-            elementData[i] = null;
-
+        Arrays.fill(elementData, 0, size, null);
         size = 0;
     }
 
@@ -665,16 +665,10 @@
                     outOfBoundsMsg(fromIndex, toIndex));
         }
         modCount++;
-        int numMoved = size - toIndex;
-        System.arraycopy(elementData, toIndex, elementData, fromIndex,
-                         numMoved);
-
-        // clear to let GC do its work
-        int newSize = size - (toIndex-fromIndex);
-        for (int i = newSize; i < size; i++) {
-            elementData[i] = null;
-        }
-        size = newSize;
+        final Object[] es = elementData;
+        final int oldSize = size;
+        System.arraycopy(es, toIndex, es, fromIndex, oldSize - toIndex);
+        Arrays.fill(es, size -= (toIndex - fromIndex), oldSize, null);
     }
 
     /**
@@ -717,8 +711,7 @@
      * @see Collection#contains(Object)
      */
     public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return batchRemove(c, false);
+        return batchRemove(c, false, 0, size);
     }
 
     /**
@@ -738,34 +731,35 @@
      * @see Collection#contains(Object)
      */
     public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return batchRemove(c, true);
+        return batchRemove(c, true, 0, size);
     }
 
-    private boolean batchRemove(Collection<?> c, boolean complement) {
-        final Object[] elementData = this.elementData;
-        int r = 0, w = 0;
-        boolean modified = false;
-        try {
-            for (; r < size; r++)
-                if (c.contains(elementData[r]) == complement)
-                    elementData[w++] = elementData[r];
-        } finally {
-            // Preserve behavioral compatibility with AbstractCollection,
-            // even if c.contains() throws.
-            if (r != size) {
-                System.arraycopy(elementData, r,
-                                 elementData, w,
-                                 size - r);
-                w += size - r;
-            }
-            if (w != size) {
-                // clear to let GC do its work
-                for (int i = w; i < size; i++)
-                    elementData[i] = null;
-                modCount += size - w;
-                size = w;
-                modified = true;
+    boolean batchRemove(Collection<?> c, boolean complement,
+                        final int from, final int end) {
+        Objects.requireNonNull(c);
+        final Object[] es = elementData;
+        final boolean modified;
+        int r;
+        // Optimize for initial run of survivors
+        for (r = from; r < end && c.contains(es[r]) == complement; r++)
+            ;
+        if (modified = (r < end)) {
+            int w = r++;
+            try {
+                for (Object e; r < end; r++)
+                    if (c.contains(e = es[r]) == complement)
+                        es[w++] = e;
+            } catch (Throwable ex) {
+                // Preserve behavioral compatibility with AbstractCollection,
+                // even if c.contains() throws.
+                System.arraycopy(es, r, es, w, end - r);
+                w += end - r;
+                throw ex;
+            } finally {
+                final int oldSize = size, deleted = end - w;
+                modCount += deleted;
+                System.arraycopy(es, end, es, w, oldSize - end);
+                Arrays.fill(es, size -= deleted, oldSize, null);
             }
         }
         return modified;
@@ -912,25 +906,21 @@
         }
 
         @Override
-        @SuppressWarnings("unchecked")
-        public void forEachRemaining(Consumer<? super E> consumer) {
-            Objects.requireNonNull(consumer);
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
             final int size = ArrayList.this.size;
             int i = cursor;
-            if (i >= size) {
-                return;
-            }
-            final Object[] elementData = ArrayList.this.elementData;
-            if (i >= elementData.length) {
-                throw new ConcurrentModificationException();
+            if (i < size) {
+                final Object[] es = elementData;
+                if (i >= es.length)
+                    throw new ConcurrentModificationException();
+                for (; i < size && modCount == expectedModCount; i++)
+                    action.accept(elementAt(es, i));
+                // update once at end to reduce heap write traffic
+                cursor = i;
+                lastRet = i - 1;
+                checkForComodification();
             }
-            while (i != size && modCount == expectedModCount) {
-                consumer.accept((E) elementData[i++]);
-            }
-            // update once at end of iteration to reduce heap write traffic
-            cursor = i;
-            lastRet = i - 1;
-            checkForComodification();
         }
 
         final void checkForComodification() {
@@ -1117,6 +1107,33 @@
             return true;
         }
 
+        public boolean removeAll(Collection<?> c) {
+            return batchRemove(c, false);
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            return batchRemove(c, true);
+        }
+
+        private boolean batchRemove(Collection<?> c, boolean complement) {
+            checkForComodification();
+            int oldSize = root.size;
+            boolean modified =
+                root.batchRemove(c, complement, offset, offset + size);
+            if (modified)
+                updateSizeAndModCount(root.size - oldSize);
+            return modified;
+        }
+
+        public boolean removeIf(Predicate<? super E> filter) {
+            checkForComodification();
+            int oldSize = root.size;
+            boolean modified = root.removeIf(filter, offset, offset + size);
+            if (modified)
+                updateSizeAndModCount(root.size - oldSize);
+            return modified;
+        }
+
         public Iterator<E> iterator() {
             return listIterator();
         }
@@ -1164,24 +1181,21 @@
                     return (E) elementData[offset + (lastRet = i)];
                 }
 
-                @SuppressWarnings("unchecked")
-                public void forEachRemaining(Consumer<? super E> consumer) {
-                    Objects.requireNonNull(consumer);
+                public void forEachRemaining(Consumer<? super E> action) {
+                    Objects.requireNonNull(action);
                     final int size = SubList.this.size;
                     int i = cursor;
-                    if (i >= size) {
-                        return;
-                    }
-                    final Object[] elementData = root.elementData;
-                    if (offset + i >= elementData.length) {
-                        throw new ConcurrentModificationException();
+                    if (i < size) {
+                        final Object[] es = root.elementData;
+                        if (offset + i >= es.length)
+                            throw new ConcurrentModificationException();
+                        for (; i < size && modCount == expectedModCount; i++)
+                            action.accept(elementAt(es, offset + i));
+                        // update once at end to reduce heap write traffic
+                        cursor = i;
+                        lastRet = i - 1;
+                        checkForComodification();
                     }
-                    while (i != size && modCount == expectedModCount) {
-                        consumer.accept((E) elementData[offset + (i++)]);
-                    }
-                    // update once at end of iteration to reduce heap write traffic
-                    lastRet = cursor = i;
-                    checkForComodification();
                 }
 
                 public int nextIndex() {
@@ -1348,15 +1362,12 @@
     public void forEach(Consumer<? super E> action) {
         Objects.requireNonNull(action);
         final int expectedModCount = modCount;
-        @SuppressWarnings("unchecked")
-        final E[] elementData = (E[]) this.elementData;
+        final Object[] es = elementData;
         final int size = this.size;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            action.accept(elementData[i]);
-        }
-        if (modCount != expectedModCount) {
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            action.accept(elementAt(es, i));
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
     }
 
     /**
@@ -1417,7 +1428,7 @@
         private int fence; // -1 until used; then one past last index
         private int expectedModCount; // initialized when fence set
 
-        /** Create new spliterator covering the given  range */
+        /** Create new spliterator covering the given range */
         ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                              int expectedModCount) {
             this.list = list; // OK if null unless traversed
@@ -1495,61 +1506,73 @@
         }
     }
 
-    @Override
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        // figure out which elements are to be removed
-        // any exception thrown from the filter predicate at this stage
-        // will leave the collection unmodified
-        int removeCount = 0;
-        final BitSet removeSet = new BitSet(size);
-        final int expectedModCount = modCount;
-        final int size = this.size;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            @SuppressWarnings("unchecked")
-            final E element = (E) elementData[i];
-            if (filter.test(element)) {
-                removeSet.set(i);
-                removeCount++;
-            }
-        }
-        if (modCount != expectedModCount) {
-            throw new ConcurrentModificationException();
-        }
+    // A tiny bit set implementation
 
-        // shift surviving elements left over the spaces left by removed elements
-        final boolean anyToRemove = removeCount > 0;
-        if (anyToRemove) {
-            final int newSize = size - removeCount;
-            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
-                i = removeSet.nextClearBit(i);
-                elementData[j] = elementData[i];
-            }
-            for (int k=newSize; k < size; k++) {
-                elementData[k] = null;  // Let gc do its work
-            }
-            this.size = newSize;
-            if (modCount != expectedModCount) {
-                throw new ConcurrentModificationException();
-            }
-            modCount++;
-        }
-
-        return anyToRemove;
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
     }
 
     @Override
-    @SuppressWarnings("unchecked")
+    public boolean removeIf(Predicate<? super E> filter) {
+        return removeIf(filter, 0, size);
+    }
+
+    /**
+     * Removes all elements satisfying the given predicate, from index
+     * i (inclusive) to index end (exclusive).
+     */
+    boolean removeIf(Predicate<? super E> filter, int i, final int end) {
+        Objects.requireNonNull(filter);
+        int expectedModCount = modCount;
+        final Object[] es = elementData;
+        // Optimize for initial run of survivors
+        for (; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        // Tolerate predicates that reentrantly access the collection for
+        // read (but writers still get CME), so traverse once to find
+        // elements to delete, a second pass to physically expunge.
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - beg);
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            expectedModCount++;
+            modCount++;
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    es[w++] = es[i];
+            final int oldSize = size;
+            System.arraycopy(es, end, es, w, oldSize - end);
+            Arrays.fill(es, size -= (end - w), oldSize, null);
+            return true;
+        } else {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return false;
+        }
+    }
+
+    @Override
     public void replaceAll(UnaryOperator<E> operator) {
         Objects.requireNonNull(operator);
         final int expectedModCount = modCount;
+        final Object[] es = elementData;
         final int size = this.size;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            elementData[i] = operator.apply((E) elementData[i]);
-        }
-        if (modCount != expectedModCount) {
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
         modCount++;
     }
 
@@ -1558,9 +1581,13 @@
     public void sort(Comparator<? super E> c) {
         final int expectedModCount = modCount;
         Arrays.sort((E[]) elementData, 0, size, c);
-        if (modCount != expectedModCount) {
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
         modCount++;
     }
+
+    void checkInvariants() {
+        // assert size >= 0;
+        // assert size == elementData.length || elementData[size] == null;
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/HashMap.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/HashMap.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1502,8 +1502,7 @@
             if (modCount != expectedModCount)
                 throw new ConcurrentModificationException();
             current = null;
-            K key = p.key;
-            removeNode(hash(key), key, null, false, false);
+            removeNode(p.hash, p.key, null, false, false);
             expectedModCount = modCount;
         }
     }
--- a/jdk/src/java.base/share/classes/java/util/Iterator.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/Iterator.java	Wed Jul 05 22:32:06 2017 +0200
@@ -76,10 +76,15 @@
     /**
      * Removes from the underlying collection the last element returned
      * by this iterator (optional operation).  This method can be called
-     * only once per call to {@link #next}.  The behavior of an iterator
-     * is unspecified if the underlying collection is modified while the
-     * iteration is in progress in any way other than by calling this
-     * method.
+     * only once per call to {@link #next}.
+     * <p>
+     * The behavior of an iterator is unspecified if the underlying collection
+     * is modified while the iteration is in progress in any way other than by
+     * calling this method, unless an overriding class has specified a
+     * concurrent modification policy.
+     * <p>
+     * The behavior of an iterator is unspecified if this method is called
+     * after a call to the {@link #forEachRemaining forEachRemaining} method.
      *
      * @implSpec
      * The default implementation throws an instance of
@@ -102,6 +107,13 @@
      * have been processed or the action throws an exception.  Actions are
      * performed in the order of iteration, if that order is specified.
      * Exceptions thrown by the action are relayed to the caller.
+     * <p>
+     * The behavior of an iterator is unspecified if the action modifies the
+     * collection in any way (even by calling the {@link #remove remove} method),
+     * unless an overriding class has specified a concurrent modification policy.
+     * <p>
+     * Subsequent behavior of an iterator is unspecified if the action throws an
+     * exception.
      *
      * @implSpec
      * <p>The default implementation behaves as if:
--- a/jdk/src/java.base/share/classes/java/util/LinkedHashMap.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/LinkedHashMap.java	Wed Jul 05 22:32:06 2017 +0200
@@ -731,8 +731,7 @@
             if (modCount != expectedModCount)
                 throw new ConcurrentModificationException();
             current = null;
-            K key = p.key;
-            removeNode(hash(key), key, null, false, false);
+            removeNode(p.hash, p.key, null, false, false);
             expectedModCount = modCount;
         }
     }
--- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java	Wed Jul 05 22:32:06 2017 +0200
@@ -42,6 +42,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
@@ -62,13 +63,14 @@
 import java.util.spi.ResourceBundleControlProvider;
 import java.util.spi.ResourceBundleProvider;
 
+import jdk.internal.loader.BootLoader;
 import jdk.internal.misc.JavaUtilResourceBundleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
+import sun.security.action.GetPropertyAction;
 import sun.util.locale.BaseLocale;
 import sun.util.locale.LocaleObjectCache;
-import sun.util.locale.provider.ResourceBundleProviderSupport;
 import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
 
 
@@ -247,7 +249,8 @@
  * used to load resource bundles. If no service provider is available, or if
  * none of the service providers returns a resource bundle and the caller module
  * doesn't have its own service provider, the {@code getBundle} factory method
- * searches for resource bundles local to the caller module. The resource bundle
+ * searches for resource bundles that are local in the caller module and that
+ * are visible to the class loader of the caller module.  The resource bundle
  * formats for local module searching are "java.class" and "java.properties".
  *
  * <h3>ResourceBundle.Control</h3>
@@ -372,6 +375,18 @@
                 public void setName(ResourceBundle bundle, String name) {
                     bundle.name = name;
                 }
+
+                @Override
+                public ResourceBundle getBundle(String baseName, Locale locale, Module module) {
+                    // use the given module as the caller to bypass the access check
+                    return getBundleImpl(module, module, getLoader(module),
+                                         baseName, locale, Control.INSTANCE);
+                }
+
+                @Override
+                public ResourceBundle newResourceBundle(Class<? extends ResourceBundle> bundleClass) {
+                    return ResourceBundleProviderHelper.newResourceBundle(bundleClass);
+                }
             });
     }
 
@@ -999,6 +1014,14 @@
      * <code>getBundle(baseName, Locale.getDefault(), module)</code>
      * </blockquote>
      *
+     * <p> Resource bundles in named modules may be encapsulated.  When
+     * the resource bundle is loaded from a provider, the caller module
+     * must have an appropriate <i>uses</i> clause in its <i>module descriptor</i>
+     * to declare that the module uses implementations of {@code "baseName"Provider}.
+     * When the resource bundle is loaded from the specified module, it is
+     * subject to the encapsulation rules specified by
+     * {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     *
      * @param baseName the base name of the resource bundle,
      *                 a fully qualified class name
      * @param module   the module for which the resource bundle is searched
@@ -1024,10 +1047,19 @@
      * Gets a resource bundle using the specified base name and locale
      * on behalf of the specified module.
      *
+     * <p> Resource bundles in named modules may be encapsulated.  When
+     * the resource bundle is loaded from a provider, the caller module
+     * must have an appropriate <i>uses</i> clause in its <i>module descriptor</i>
+     * to declare that the module uses implementations of {@code "baseName"Provider}.
+     * When the resource bundle is loaded from the specified module, it is
+     * subject to the encapsulation rules specified by
+     * {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     *
      * <p>
      * If the given {@code module} is a named module, this method will
      * load the service providers for {@link java.util.spi.ResourceBundleProvider}
-     * and also resource bundles local in the given module (refer to the
+     * and also resource bundles that are local in the given module or that
+     * are visible to the class loader of the given module (refer to the
      * <a href="#bundleprovider">Resource Bundles in Named Modules</a> section
      * for details).
      *
@@ -1035,9 +1067,8 @@
      * If the given {@code module} is an unnamed module, then this method is
      * equivalent to calling {@link #getBundle(String, Locale, ClassLoader)
      * getBundle(baseName, targetLocale, module.getClassLoader()} to load
-     * resource bundles that are in unnamed modules visible to the
-     * class loader of the given unnamed module.  It will not find resource
-     * bundles from named modules.
+     * resource bundles that are visible to the class loader of the given
+     * unnamed module.
      *
      * @param baseName the base name of the resource bundle,
      *                 a fully qualified class name
@@ -1126,7 +1157,8 @@
      * Resource bundles in a named module are private to that module.  If
      * the caller is in a named module, this method will find resource bundles
      * from the service providers of {@link java.util.spi.ResourceBundleProvider}
-     * and also find resource bundles private to the caller's module.
+     * and also find resource bundles that are in the caller's module or
+     * that are visible to the given class loader.
      * If the caller is in a named module and the given {@code loader} is
      * different than the caller's class loader, or if the caller is not in
      * a named module, this method will not find resource bundles from named
@@ -1587,13 +1619,20 @@
             // get resource bundles for a named module only
             // if loader is the module's class loader
             if (loader == ml || (ml == null && loader == RBClassLoader.INSTANCE)) {
-                return getBundleImpl(baseName, locale, loader, module, control);
+                return getBundleImpl(module, module, loader, baseName, locale, control);
             }
         }
         // find resource bundles from unnamed module
-        Module module = loader != null ? loader.getUnnamedModule()
-                                       : ClassLoader.getSystemClassLoader().getUnnamedModule();
-        return getBundleImpl(baseName, locale, loader, module, control);
+        Module unnamedModule = loader != null
+            ? loader.getUnnamedModule()
+            : ClassLoader.getSystemClassLoader().getUnnamedModule();
+
+        if (caller == null) {
+            throw new InternalError("null caller");
+        }
+
+        Module callerModule = caller.getModule();
+        return getBundleImpl(callerModule, unnamedModule, loader, baseName, locale, control);
     }
 
     private static ResourceBundle getBundleFromModule(Class<?> caller,
@@ -1602,19 +1641,21 @@
                                                       Locale locale,
                                                       Control control) {
         Objects.requireNonNull(module);
-        if (caller.getModule() != module) {
+        Module callerModule = caller.getModule();
+        if (callerModule != module) {
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
                 sm.checkPermission(GET_CLASSLOADER_PERMISSION);
             }
         }
-        return getBundleImpl(baseName, locale, getLoader(module), module, control);
+        return getBundleImpl(callerModule, module, getLoader(module), baseName, locale, control);
     }
 
-    private static ResourceBundle getBundleImpl(String baseName,
+    private static ResourceBundle getBundleImpl(Module callerModule,
+                                                Module module,
+                                                ClassLoader loader,
+                                                String baseName,
                                                 Locale locale,
-                                                ClassLoader loader,
-                                                Module module,
                                                 Control control) {
         if (locale == null || control == null) {
             throw new NullPointerException();
@@ -1661,7 +1702,8 @@
                 throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
             }
 
-            bundle = findBundle(cacheKey, module, candidateLocales, formats, 0, control, baseBundle);
+            bundle = findBundle(callerModule, module, cacheKey,
+                                candidateLocales, formats, 0, control, baseBundle);
 
             // If the loaded bundle is the base bundle and exactly for the
             // requested locale or the only candidate locale, then take the
@@ -1710,8 +1752,9 @@
         return valid;
     }
 
-    private static ResourceBundle findBundle(CacheKey cacheKey,
+    private static ResourceBundle findBundle(Module callerModule,
                                              Module module,
+                                             CacheKey cacheKey,
                                              List<Locale> candidateLocales,
                                              List<String> formats,
                                              int index,
@@ -1720,7 +1763,8 @@
         Locale targetLocale = candidateLocales.get(index);
         ResourceBundle parent = null;
         if (index != candidateLocales.size() - 1) {
-            parent = findBundle(cacheKey, module, candidateLocales, formats, index + 1,
+            parent = findBundle(callerModule, module, cacheKey,
+                                candidateLocales, formats, index + 1,
                                 control, baseBundle);
         } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
             return baseBundle;
@@ -1764,10 +1808,10 @@
 
         if (bundle != NONEXISTENT_BUNDLE) {
             CacheKey constKey = (CacheKey) cacheKey.clone();
-
+            trace("findBundle: %d %s %s formats: %s%n", index, candidateLocales, cacheKey, formats);
             try {
                 if (module.isNamed()) {
-                    bundle = loadBundle(cacheKey, formats, control, module);
+                    bundle = loadBundle(cacheKey, formats, control, module, callerModule);
                 } else {
                     bundle = loadBundle(cacheKey, formats, control, expiredBundle);
                 }
@@ -1794,39 +1838,60 @@
 
     private static final String UNKNOWN_FORMAT = "";
 
+
     /*
      * Loads a ResourceBundle in named modules
      */
     private static ResourceBundle loadBundle(CacheKey cacheKey,
                                              List<String> formats,
                                              Control control,
-                                             Module module) {
+                                             Module module,
+                                             Module callerModule) {
         String baseName = cacheKey.getName();
         Locale targetLocale = cacheKey.getLocale();
 
         ResourceBundle bundle = null;
         if (cacheKey.hasProviders()) {
-            bundle = loadBundleFromProviders(baseName, targetLocale,
-                                             cacheKey.getProviders(), cacheKey);
+            if (callerModule == module) {
+                bundle = loadBundleFromProviders(baseName,
+                                                 targetLocale,
+                                                 cacheKey.getProviders(),
+                                                 cacheKey);
+            } else {
+                // load from provider if the caller module has access to the
+                // service type and also declares `uses`
+                ClassLoader loader = getLoader(module);
+                Class<ResourceBundleProvider> svc =
+                    getResourceBundleProviderType(baseName, loader);
+                if (svc != null
+                        && Reflection.verifyModuleAccess(callerModule, svc)
+                        && callerModule.canUse(svc)) {
+                    bundle = loadBundleFromProviders(baseName,
+                                                     targetLocale,
+                                                     cacheKey.getProviders(),
+                                                      cacheKey);
+                }
+            }
+
             if (bundle != null) {
                 cacheKey.setFormat(UNKNOWN_FORMAT);
             }
         }
+
         // If none of providers returned a bundle and the caller has no provider,
-        // look up module-local bundles.
+        // look up module-local bundles or from the class path
         if (bundle == null && !cacheKey.callerHasProvider()) {
-            String bundleName = control.toBundleName(baseName, targetLocale);
             for (String format : formats) {
                 try {
                     switch (format) {
                     case "java.class":
-                        PrivilegedAction<ResourceBundle> pa = ()
-                                -> ResourceBundleProviderSupport
-                                    .loadResourceBundle(module, bundleName);
-                        bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                        bundle = ResourceBundleProviderHelper
+                            .loadResourceBundle(callerModule, module, baseName, targetLocale);
+
                         break;
                     case "java.properties":
-                        bundle = ResourceBundleProviderSupport.loadPropertyResourceBundle(module, bundleName);
+                        bundle = ResourceBundleProviderHelper
+                            .loadPropertyResourceBundle(callerModule, module, baseName, targetLocale);
                         break;
                     default:
                         throw new InternalError("unexpected format: " + format);
@@ -1844,29 +1909,46 @@
         return bundle;
     }
 
+    /**
+     * Returns a ServiceLoader that will find providers that are bound to
+     * a given named module.
+     */
     private static ServiceLoader<ResourceBundleProvider> getServiceLoader(Module module,
-                                                                          String baseName) {
+                                                                          String baseName)
+    {
         if (!module.isNamed()) {
             return null;
         }
-        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
-        ClassLoader loader = AccessController.doPrivileged(pa);
-        return getServiceLoader(module, loader, baseName);
+
+        ClassLoader loader = getLoader(module);
+        Class<ResourceBundleProvider> service =
+                getResourceBundleProviderType(baseName, loader);
+        if (service != null && Reflection.verifyModuleAccess(module, service)) {
+            try {
+                // locate providers that are visible to the class loader
+                // ServiceConfigurationError will be thrown if the module
+                // does not declare `uses` the service type
+                return ServiceLoader.load(service, loader, module);
+            } catch (ServiceConfigurationError e) {
+                // "uses" not declared
+                return null;
+            }
+        }
+        return null;
     }
 
-        /**
-         * Returns a ServiceLoader that will find providers that are bound to
-         * a given module that may be named or unnamed.
-         */
-    private static ServiceLoader<ResourceBundleProvider> getServiceLoader(Module module,
-                                                                          ClassLoader loader,
-                                                                          String baseName)
+    /**
+     * Returns the service type of the given baseName that is visible
+     * to the given class loader
+     */
+    private static Class<ResourceBundleProvider>
+            getResourceBundleProviderType(String baseName, ClassLoader loader)
     {
         // Look up <baseName> + "Provider"
         String providerName = baseName + "Provider";
         // Use the class loader of the getBundle caller so that the caller's
         // visibility of the provider type is checked.
-        Class<ResourceBundleProvider> service = AccessController.doPrivileged(
+        return AccessController.doPrivileged(
             new PrivilegedAction<>() {
                 @Override
                 public Class<ResourceBundleProvider> run() {
@@ -1881,16 +1963,6 @@
                     return null;
                 }
             });
-
-        if (service != null && Reflection.verifyModuleAccess(module, service)) {
-            try {
-                return ServiceLoader.load(service, loader, module);
-            } catch (ServiceConfigurationError e) {
-                // "uses" not declared: load bundle local in the module
-                return null;
-            }
-        }
-        return null;
     }
 
     /**
@@ -1914,6 +1986,7 @@
                                     cacheKey.callerHasProvider = Boolean.TRUE;
                                 }
                                 ResourceBundle bundle = provider.getBundle(baseName, locale);
+                                trace("provider %s %s locale: %s bundle: %s%n", provider, baseName, locale, bundle);
                                 if (bundle != null) {
                                     return bundle;
                                 }
@@ -3016,6 +3089,14 @@
          * indicates that this method is being called because the previously
          * loaded resource bundle has expired.
          *
+         * @implSpec
+         *
+         * Resource bundles in named modules are subject to the encapsulation
+         * rules specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+         * A resource bundle in a named module visible to the given class loader
+         * is accessible when the package of the resource file corresponding
+         * to the resource bundle is open unconditionally.
+         *
          * <p>The default implementation instantiates a
          * <code>ResourceBundle</code> as follows.
          *
@@ -3026,12 +3107,15 @@
          * locale)}.</li>
          *
          * <li>If <code>format</code> is <code>"java.class"</code>, the
-         * {@link Class} specified by the bundle name is loaded by calling
-         * {@link ClassLoader#loadClass(String)}. Then, a
-         * <code>ResourceBundle</code> is instantiated by calling {@link
-         * Class#newInstance()}.  Note that the <code>reload</code> flag is
-         * ignored for loading class-based resource bundles in this default
-         * implementation.</li>
+         * {@link Class} specified by the bundle name is loaded with the
+         * given class loader. If the {@code Class} is found and accessible
+         * then the <code>ResourceBundle</code> is instantiated.  The
+         * resource bundle is accessible if the package of the bundle class file
+         * is open unconditionally; otherwise, {@code IllegalAccessException}
+         * will be thrown.
+         * Note that the <code>reload</code> flag is ignored for loading
+         * class-based resource bundles in this default implementation.
+         * </li>
          *
          * <li>If <code>format</code> is <code>"java.properties"</code>,
          * {@link #toResourceName(String, String) toResourceName(bundlename,
@@ -3105,7 +3189,6 @@
             /*
              * Legacy mechanism to locate resource bundle in unnamed module only
              * that is visible to the given loader and accessible to the given caller.
-             * This only finds resources on the class path but not in named modules.
              */
             String bundleName = toBundleName(baseName, locale);
             ResourceBundle bundle = null;
@@ -3117,18 +3200,15 @@
                     if (ResourceBundle.class.isAssignableFrom(c)) {
                         @SuppressWarnings("unchecked")
                         Class<ResourceBundle> bundleClass = (Class<ResourceBundle>)c;
+                        Module m = bundleClass.getModule();
 
-                        // This doesn't allow unnamed modules to find bundles in
-                        // named modules other than via the service loader mechanism.
-                        // Otherwise, this will make the newBundle method to be
-                        // caller-sensitive in order to verify access check.
-                        // So migrating resource bundles to named module can't
-                        // just export the package (in general, legacy resource
-                        // bundles have split package if they are packaged separate
-                        // from the consumer.)
-                        if (bundleClass.getModule().isNamed()) {
-                            throw new IllegalAccessException("unnamed modules can't load " + bundleName
-                                     + " in named module " + bundleClass.getModule().getName());
+                        // To access a resource bundle in a named module,
+                        // either class-based or properties-based, the resource
+                        // bundle must be opened unconditionally,
+                        // same rule as accessing a resource file.
+                        if (m.isNamed() && !m.isOpen(bundleClass.getPackageName())) {
+                            throw new IllegalAccessException("unnamed module can't load " +
+                                bundleClass.getName() + " in " + m.toString());
                         }
                         try {
                             // bundle in a unnamed module
@@ -3502,4 +3582,173 @@
             return null;
         }
     }
+
+    private static class ResourceBundleProviderHelper {
+        /**
+         * Returns a new ResourceBundle instance of the given bundleClass
+         */
+        static ResourceBundle newResourceBundle(Class<? extends ResourceBundle> bundleClass) {
+            try {
+                @SuppressWarnings("unchecked")
+                Constructor<? extends ResourceBundle> ctor =
+                    bundleClass.getConstructor();
+                if (!Modifier.isPublic(ctor.getModifiers())) {
+                    return null;
+                }
+                // java.base may not be able to read the bundleClass's module.
+                PrivilegedAction<Void> pa = () -> { ctor.setAccessible(true); return null;};
+                AccessController.doPrivileged(pa);
+                try {
+                    return ctor.newInstance((Object[]) null);
+                } catch (InvocationTargetException e) {
+                    uncheckedThrow(e);
+                } catch (InstantiationException | IllegalAccessException e) {
+                    throw new InternalError(e);
+                }
+            } catch (NoSuchMethodException e) {
+                throw new InternalError(e);
+            }
+            return null;
+        }
+
+        /**
+         * Loads a {@code ResourceBundle} of the given {@code bundleName} local to
+         * the given {@code module}. If not found, search the bundle class
+         * that is visible from the module's class loader.
+         *
+         * The caller module is used for access check only.
+         */
+        static ResourceBundle loadResourceBundle(Module callerModule,
+                                                 Module module,
+                                                 String baseName,
+                                                 Locale locale)
+        {
+            String bundleName = Control.INSTANCE.toBundleName(baseName, locale);
+            try {
+                PrivilegedAction<Class<?>> pa = () -> Class.forName(module, bundleName);
+                Class<?> c = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                trace("local in %s %s caller %s: %s%n", module, bundleName, callerModule, c);
+
+                if (c == null) {
+                    // if not found from the given module, locate resource bundle
+                    // that is visible to the module's class loader
+                    ClassLoader loader = getLoader(module);
+                    if (loader != null) {
+                        c = Class.forName(bundleName, false, loader);
+                    } else {
+                        c = BootLoader.loadClassOrNull(bundleName);
+                    }
+                    trace("loader for %s %s caller %s: %s%n", module, bundleName, callerModule, c);
+                }
+
+                if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
+                    @SuppressWarnings("unchecked")
+                    Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
+                    Module m = bundleClass.getModule();
+                    if (!isAccessible(callerModule, m, bundleClass.getPackageName())) {
+                        trace("   %s does not have access to %s/%s%n", callerModule,
+                              m.getName(), bundleClass.getPackageName());
+                        return null;
+                    }
+
+                    return newResourceBundle(bundleClass);
+                }
+            } catch (ClassNotFoundException e) {}
+            return null;
+        }
+
+        /**
+         * Tests if resources of the given package name from the given module are
+         * open to the caller module.
+         */
+        static boolean isAccessible(Module callerModule, Module module, String pn) {
+            if (!module.isNamed() || callerModule == module)
+                return true;
+
+            return module.isOpen(pn, callerModule);
+        }
+
+        /**
+         * Loads properties of the given {@code bundleName} local in the given
+         * {@code module}.  If the .properties is not found or not open
+         * to the caller module to access, it will find the resource that
+         * is visible to the module's class loader.
+         *
+         * The caller module is used for access check only.
+         */
+        static ResourceBundle loadPropertyResourceBundle(Module callerModule,
+                                                         Module module,
+                                                         String baseName,
+                                                         Locale locale)
+            throws IOException
+        {
+            String bundleName = Control.INSTANCE.toBundleName(baseName, locale);
+
+            PrivilegedAction<InputStream> pa = () -> {
+                try {
+                    String resourceName = Control.INSTANCE
+                        .toResourceName0(bundleName, "properties");
+                    if (resourceName == null) {
+                        return null;
+                    }
+                    trace("local in %s %s caller %s%n", module, resourceName, callerModule);
+
+                    // if the package is in the given module but not opened
+                    // locate it from the given module first.
+                    String pn = toPackageName(bundleName);
+                    trace("   %s/%s is accessible to %s : %s%n",
+                            module.getName(), pn, callerModule,
+                            isAccessible(callerModule, module, pn));
+                    if (isAccessible(callerModule, module, pn)) {
+                        InputStream in = module.getResourceAsStream(resourceName);
+                        if (in != null) {
+                            return in;
+                        }
+                    }
+
+                    ClassLoader loader = module.getClassLoader();
+                    trace("loader for %s %s caller %s%n", module, resourceName, callerModule);
+
+                    try {
+                        if (loader != null) {
+                            return loader.getResourceAsStream(resourceName);
+                        } else {
+                            URL url = BootLoader.findResource(resourceName);
+                            if (url != null) {
+                                return url.openStream();
+                            }
+                        }
+                    } catch (Exception e) {}
+                    return null;
+
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
+                }
+            };
+
+            try (InputStream stream = AccessController.doPrivileged(pa)) {
+                if (stream != null) {
+                    return new PropertyResourceBundle(stream);
+                } else {
+                    return null;
+                }
+            } catch (UncheckedIOException e) {
+                throw e.getCause();
+            }
+        }
+
+        private static String toPackageName(String bundleName) {
+            int i = bundleName.lastIndexOf('.');
+            return i != -1 ? bundleName.substring(0, i) : "";
+        }
+
+    }
+
+    private static final boolean TRACE_ON = Boolean.valueOf(
+        GetPropertyAction.privilegedGetProperty("resource.bundle.debug", "false"));
+
+    private static void trace(String format, Object... params) {
+        if (TRACE_ON)
+            System.out.format(format, params);
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,23 +32,28 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Module;
 import java.net.URL;
 import java.net.URLConnection;
+import java.security.AccessControlContext;
 import java.security.AccessController;
-import java.security.AccessControlContext;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import jdk.internal.loader.BootLoader;
-import jdk.internal.loader.Loader;
-import jdk.internal.loader.LoaderPool;
 import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.JavaLangReflectModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 import jdk.internal.module.ServicesCatalog;
 import jdk.internal.module.ServicesCatalog.ServiceProvider;
-
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 
@@ -76,21 +81,49 @@
  * request together with code that can create the actual provider on demand.
  * The details of provider classes tend to be highly service-specific; no
  * single class or interface could possibly unify them, so no such type is
- * defined here. A requirement enforced by this facility is that each provider
- * class must have a {@code public} zero-argument constructor.
+ * defined here.
+ *
+ * <p> Providers deployed as explicit modules on the module path are
+ * instantiated by a <em>provider factory</em> or directly via the provider's
+ * constructor. In the module declaration then the class name specified in the
+ * <i>provides</i> clause is a provider factory if it is public and defines a
+ * public static no-args method named "{@code provider}". The return type of
+ * the method must be assignable to the <i>service</i> type. If the class is
+ * not a provider factory then it is public with a public zero-argument
+ * constructor. The requirement that the provider factory or provider class
+ * be public helps to document the intent that the provider will be
+ * instantiated by the service-provider loading facility.
+ *
+ * <p> As an example, suppose a module declares the following:
+ *
+ * <pre>{@code
+ *     provides com.example.CodecSet with com.example.impl.StandardCodecs;
+ *     provides com.example.CodecSet with com.example.impl.ExtendedCodecsFactory;
+ * }</pre>
+ *
+ * <p> where {@code com.example.CodecSet} is the service type, {@code
+ * com.example.impl.StandardCodecs} is a provider class that is public with a
+ * public no-args constructor, {@code com.example.impl.ExtendedCodecsFactory}
+ * is a public class that defines a public static no-args method named
+ * "{@code provider}" with a return type that is {@code CodecSet} or a subtype
+ * of. For this example then {@code StandardCodecs}'s no-arg constructor will
+ * be used to instantiate {@code StandardCodecs}. {@code ExtendedCodecsFactory}
+ * will be treated as a provider factory and {@code
+ * ExtendedCodecsFactory.provider()} will be invoked to obtain the provider.
+ *
+ * <p> Providers deployed on the class path or as {@link
+ * java.lang.module.ModuleDescriptor#isAutomatic automatic-modules} on the
+ * module path must have a public zero-argument constructor.
  *
  * <p> An application or library using this loading facility and developed
- * and deployed as a named module must have an appropriate <i>uses</i> clause
- * in its <i>module descriptor</i> to declare that the module uses
+ * and deployed as an explicit module must have an appropriate <i>uses</i>
+ * clause in its <i>module descriptor</i> to declare that the module uses
  * implementations of the service. A corresponding requirement is that a
  * provider deployed as a named module must have an appropriate
  * <i>provides</i> clause in its module descriptor to declare that the module
  * provides an implementation of the service. The <i>uses</i> and
- * <i>provides</i> allow consumers of a service to be <i>linked</i> to
- * providers of the service. In the case of {@code load} methods that locate
- * service providers using a class loader, then provider modules defined to
- * that class loader, or a class loader <i>reachable</i> using {@link
- * ClassLoader#getParent() parent} delegation, will be located.
+ * <i>provides</i> allow consumers of a service to be <i>linked</i> to modules
+ * containing providers of the service.
  *
  * <p> A service provider that is packaged as a JAR file for the class path is
  * identified by placing a <i>provider-configuration file</i> in the resource
@@ -114,27 +147,116 @@
  *
  * <p> Providers are located and instantiated lazily, that is, on demand.  A
  * service loader maintains a cache of the providers that have been loaded so
- * far.  Each invocation of the {@link #iterator iterator} method returns an
- * iterator that first yields all of the elements of the cache, in
- * instantiation order, and then lazily locates and instantiates any remaining
- * providers, adding each one to the cache in turn.  The cache can be cleared
+ * far. Each invocation of the {@link #iterator iterator} method returns an
+ * iterator that first yields all of the elements cached from previous
+ * iteration, in instantiation order, and then lazily locates and instantiates
+ * any remaining providers, adding each one to the cache in turn.  Similarly,
+ * each invocation of the {@link #stream stream} method returns a stream that
+ * first processes all providers loaded by previous stream operations, in load
+ * order, and then lazily locates any remaining providers. Caches are cleared
  * via the {@link #reload reload} method.
  *
+ * <h2> Locating providers </h2>
+ *
+ * <p> The {@code load} methods locate providers using a class loader or module
+ * {@link Layer layer}. When locating providers using a class loader then
+ * providers in both named and unnamed modules may be located. When locating
+ * providers using a module layer then only providers in named modules in
+ * the layer (or parent layers) are located.
+ *
+ * <p> When locating providers using a class loader then any providers in named
+ * modules defined to the class loader, or any class loader that is reachable
+ * via parent delegation, are located. Additionally, providers in module layers
+ * other than the {@link Layer#boot() boot} layer, where the module layer
+ * contains modules defined to the class loader, or any class loader reachable
+ * via parent delegation, are also located. For example, suppose there is a
+ * module layer where each module is defined to its own class loader (see {@link
+ * Layer#defineModulesWithManyLoaders defineModulesWithManyLoaders}). If the
+ * {@code load} method is invoked to locate providers using any of these class
+ * loaders for this layer then it will locate all of the providers in that
+ * layer, irrespective of their defining class loader.
+ *
+ * <p> In the case of unnamed modules then the service configuration files are
+ * located using the class loader's {@link ClassLoader#getResources(String)
+ * ClassLoader.getResources(String)} method. Any providers listed should be
+ * visible via the class loader specified to the {@code load} method. If a
+ * provider in a named module is listed then it is ignored - this is to avoid
+ * duplicates that would otherwise arise when a module has both a
+ * <i>provides</i> clause and a service configuration file in {@code
+ * META-INF/services} that lists the same provider.
+ *
+ * <h2> Ordering </h2>
+ *
+ * <p> Service loaders created to locate providers using a {@code ClassLoader}
+ * locate providers as follows:
+ * <ul>
+ *     <li> Providers in named modules are located before providers on the
+ *     class path (or more generally, unnamed modules). </li>
+ *
+ *     <li> When locating providers in named modules then the service loader
+ *     will locate providers in modules defined to the class loader, then its
+ *     parent class loader, its parent parent, and so on to the bootstrap class
+ *     loader. If a {@code ClassLoader}, or any class loader in the parent
+ *     delegation chain, defines modules in a custom module {@link Layer} then
+ *     all providers in that layer are located, irrespective of their class
+ *     loader. The ordering of modules defined to the same class loader, or the
+ *     ordering of modules in a layer, is not defined. </li>
+ *
+ *     <li> If a named module declares more than one provider then the providers
+ *     are located in the order that they appear in the {@code provides} table of
+ *     the {@code Module} class file attribute ({@code module-info.class}). </li>
+ *
+ *     <li> When locating providers in unnamed modules then the ordering is
+ *     based on the order that the class loader's {@link
+ *     ClassLoader#getResources(String) ClassLoader.getResources(String)}
+ *     method finds the service configuration files. </li>
+ * </ul>
+ *
+ * <p> Service loaders created to locate providers in a module {@link Layer}
+ * will first locate providers in the layer, before locating providers in
+ * parent layers. Traversal of parent layers is depth-first with each layer
+ * visited at most once. For example, suppose L0 is the boot layer, L1 and
+ * L2 are custom layers with L0 as their parent. Now suppose that L3 is
+ * created with L1 and L2 as the parents (in that order). Using a service
+ * loader to locate providers with L3 as the content will locate providers
+ * in the following order: L3, L1, L0, L2. The ordering of modules in a layer
+ * is not defined.
+ *
+ * <h2> Selection and filtering </h2>
+ *
+ * <p> Selecting a provider or filtering providers will usually involve invoking
+ * a provider method. Where selection or filtering based on the provider class is
+ * needed then it can be done using a {@link #stream() stream}. For example, the
+ * following collects the providers that have a specific annotation:
+ * <pre>{@code
+ *     Set<CodecSet> providers = ServiceLoader.load(CodecSet.class)
+ *            .stream()
+ *            .filter(p -> p.type().isAnnotationPresent(Managed.class))
+ *            .map(Provider::get)
+ *            .collect(Collectors.toSet());
+ * }</pre>
+ *
+ * <h2> Security </h2>
+ *
  * <p> Service loaders always execute in the security context of the caller
- * of the iterator methods and may also be restricted by the security
+ * of the iterator or stream methods and may also be restricted by the security
  * context of the caller that created the service loader.
  * Trusted system code should typically invoke the methods in this class, and
  * the methods of the iterators which they return, from within a privileged
  * security context.
  *
+ * <h2> Concurrency </h2>
+ *
  * <p> Instances of this class are not safe for use by multiple concurrent
  * threads.
  *
- * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * <h2> Null handling </h2>
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
  * method in this class will cause a {@link NullPointerException} to be thrown.
  *
- * <p><span style="font-weight: bold; padding-right: 1em">Example</span>
- * Suppose we have a service type <tt>com.example.CodecSet</tt> which is
+ * <h2> Example </h2>
+ * <p> Suppose we have a service type <tt>com.example.CodecSet</tt> which is
  * intended to represent sets of encoder/decoder pairs for some protocol.  In
  * this case it is an abstract class with two abstract methods:
  *
@@ -218,11 +340,12 @@
 public final class ServiceLoader<S>
     implements Iterable<S>
 {
-    private static final String PREFIX = "META-INF/services/";
-
     // The class or interface representing the service being loaded
     private final Class<S> service;
 
+    // The class of the service type
+    private final String serviceName;
+
     // The module Layer used to locate providers; null when locating
     // providers using a class loader
     private final Layer layer;
@@ -234,75 +357,86 @@
     // The access control context taken when the ServiceLoader is created
     private final AccessControlContext acc;
 
-    // Cached providers, in instantiation order
-    private List<S> providers = new ArrayList<>();
+    // The lazy-lookup iterator for iterator operations
+    private Iterator<Provider<S>> lookupIterator1;
+    private final List<S> instantiatedProviders = new ArrayList<>();
 
-    // The class names of the cached providers, only used when locating
-    // service providers via a class loader
-    private Set<String> providerNames = new HashSet<>();
+    // The lazy-lookup iterator for stream operations
+    private Iterator<Provider<S>> lookupIterator2;
+    private final List<Provider<S>> loadedProviders = new ArrayList<>();
+    private boolean loadedAllProviders; // true when all providers loaded
 
     // Incremented when reload is called
     private int reloadCount;
 
-    // the service iterator when locating services via a module layer
-    private LayerLookupIterator layerLookupIterator;
-
-    // The module services iterator when locating services in modules
-    // defined to a class loader
-    private ModuleServicesIterator moduleServicesIterator;
-
-    // The current lazy-lookup iterator for locating legacy provider on the
-    // class path via a class loader
-    private LazyClassPathIterator lazyClassPathIterator;
-
+    private static JavaLangAccess LANG_ACCESS;
+    private static JavaLangReflectModuleAccess JLRM_ACCESS;
+    static {
+        LANG_ACCESS = SharedSecrets.getJavaLangAccess();
+        JLRM_ACCESS = SharedSecrets.getJavaLangReflectModuleAccess();
+    }
 
     /**
-     * Clear this loader's provider cache so that all providers will be
-     * reloaded.
+     * Represents a service provider located by {@code ServiceLoader}.
+     *
+     * <p> When using a loader's {@link ServiceLoader#stream() stream()} method
+     * then the elements are of type {@code Provider}. This allows processing
+     * to select or filter on the provider class without instantiating the
+     * provider. </p>
      *
-     * <p> After invoking this method, subsequent invocations of the {@link
-     * #iterator() iterator} method will lazily look up and instantiate
-     * providers from scratch, just as is done by a newly-created loader.
-     *
-     * <p> This method is intended for use in situations in which new providers
-     * can be installed into a running Java virtual machine.
+     * @param  <S> The service type
+     * @since 9
      */
-    public void reload() {
-        providers.clear();
+    public static interface Provider<S> extends Supplier<S> {
+        /**
+         * Returns the provider type. There is no guarantee that this type is
+         * accessible or that it has a public no-args constructor. The {@link
+         * #get() get()} method should be used to obtain the provider instance.
+         *
+         * <p> When a module declares that the provider class is created by a
+         * provider factory then this method returns the return type of its
+         * public static "{@code provider()}" method.
+         *
+         * @return The provider type
+         */
+        Class<? extends S> type();
 
-        assert layer == null || loader == null;
-        if (layer != null) {
-            layerLookupIterator = new LayerLookupIterator();
-        } else {
-            providerNames.clear();
-            moduleServicesIterator = new ModuleServicesIterator();
-            lazyClassPathIterator = new LazyClassPathIterator();
-        }
-
-        reloadCount++;
+        /**
+         * Returns an instance of the provider.
+         *
+         * @return An instance of the provider.
+         *
+         * @throws ServiceConfigurationError
+         *         If the service provider cannot be instantiated, or in the
+         *         case of a provider factory, the public static
+         *         "{@code provider()}" method returns {@code null} or throws
+         *         an error or exception. The {@code ServiceConfigurationError}
+         *         will carry an appropriate cause where possible.
+         */
+        @Override S get();
     }
 
-
     /**
      * Initializes a new instance of this class for locating service providers
      * in a module Layer.
      *
      * @throws ServiceConfigurationError
-     *         If {@code svc} is not accessible to {@code caller} or that the
-     *         caller's module does not declare that it uses the service type.
+     *         If {@code svc} is not accessible to {@code caller} or the caller
+     *         module does not use the service type.
      */
     private ServiceLoader(Class<?> caller, Layer layer, Class<S> svc) {
-
-        checkModule(caller.getModule(), svc);
+        Objects.requireNonNull(caller);
+        Objects.requireNonNull(layer);
+        Objects.requireNonNull(svc);
+        checkCaller(caller, svc);
 
         this.service = svc;
+        this.serviceName = svc.getName();
         this.layer = layer;
         this.loader = null;
         this.acc = (System.getSecurityManager() != null)
                 ? AccessController.getContext()
                 : null;
-
-        reload();
     }
 
     /**
@@ -310,23 +444,23 @@
      * via a class loader.
      *
      * @throws ServiceConfigurationError
-     *         If {@code svc} is not accessible to {@code caller} or that the
-     *         caller's module does not declare that it uses the service type.
+     *         If {@code svc} is not accessible to {@code caller} or the caller
+     *         module does not use the service type.
      */
-    private ServiceLoader(Module callerModule, Class<S> svc, ClassLoader cl) {
-        if (VM.isBooted()) {
+    private ServiceLoader(Class<?> caller, Class<S> svc, ClassLoader cl) {
+        Objects.requireNonNull(svc);
 
-            checkModule(callerModule, svc);
-
+        if (VM.isBooted()) {
+            checkCaller(caller, svc);
             if (cl == null) {
                 cl = ClassLoader.getSystemClassLoader();
             }
-
         } else {
 
             // if we get here then it means that ServiceLoader is being used
             // before the VM initialization has completed. At this point then
             // only code in the java.base should be executing.
+            Module callerModule = caller.getModule();
             Module base = Object.class.getModule();
             Module svcModule = svc.getModule();
             if (callerModule != base || svcModule != base) {
@@ -338,39 +472,55 @@
         }
 
         this.service = svc;
+        this.serviceName = svc.getName();
         this.layer = null;
         this.loader = cl;
         this.acc = (System.getSecurityManager() != null)
                 ? AccessController.getContext()
                 : null;
-
-        reload();
     }
 
-    private ServiceLoader(Class<?> caller, Class<S> svc, ClassLoader cl) {
-        this(caller.getModule(), svc, cl);
+    /**
+     * Initializes a new instance of this class for locating service providers
+     * via a class loader.
+     *
+     * @apiNote For use by ResourceBundle
+     *
+     * @throws ServiceConfigurationError
+     *         If the caller module does not use the service type.
+     */
+    private ServiceLoader(Module callerModule, Class<S> svc, ClassLoader cl) {
+        if (!callerModule.canUse(svc)) {
+            fail(svc, callerModule + " does not declare `uses`");
+        }
+
+        this.service = Objects.requireNonNull(svc);
+        this.serviceName = svc.getName();
+        this.layer = null;
+        this.loader = cl;
+        this.acc = (System.getSecurityManager() != null)
+                ? AccessController.getContext()
+                : null;
     }
 
-
-
     /**
      * Checks that the given service type is accessible to types in the given
-     * module, and check that the module declare that it uses the service type.
+     * module, and check that the module declare that it uses the service type. ??
      */
-    private static void checkModule(Module module, Class<?> svc) {
+    private static void checkCaller(Class<?> caller, Class<?> svc) {
+        Module callerModule = caller.getModule();
 
-        // Check that the service type is in a package that is
-        // exported to the caller.
-        if (!Reflection.verifyModuleAccess(module, svc)) {
-            fail(svc, "not accessible to " + module);
+        // Check access to the service type
+        int mods = svc.getModifiers();
+        if (!Reflection.verifyMemberAccess(caller, svc, null, mods)) {
+            fail(svc, "service type not accessible to " + callerModule);
         }
 
         // If the caller is in a named module then it should "uses" the
         // service type
-        if (!module.canUse(svc)) {
-            fail(svc, "use not declared in " + module);
+        if (!callerModule.canUse(svc)) {
+            fail(svc, callerModule + " does not declare `uses`");
         }
-
     }
 
     private static void fail(Class<?> service, String msg, Throwable cause)
@@ -392,310 +542,422 @@
         fail(service, u + ":" + line + ": " + msg);
     }
 
-    // Parse a single line from the given configuration file, adding the name
-    // on the line to the names list.
-    //
-    private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
-                          List<String> names)
-        throws IOException, ServiceConfigurationError
-    {
-        String ln = r.readLine();
-        if (ln == null) {
-            return -1;
-        }
-        int ci = ln.indexOf('#');
-        if (ci >= 0) ln = ln.substring(0, ci);
-        ln = ln.trim();
-        int n = ln.length();
-        if (n != 0) {
-            if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
-                fail(service, u, lc, "Illegal configuration-file syntax");
-            int cp = ln.codePointAt(0);
-            if (!Character.isJavaIdentifierStart(cp))
-                fail(service, u, lc, "Illegal provider-class name: " + ln);
-            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
-                cp = ln.codePointAt(i);
-                if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
-                    fail(service, u, lc, "Illegal provider-class name: " + ln);
-            }
-            if (!providerNames.contains(ln) && !names.contains(ln))
-                names.add(ln);
-        }
-        return lc + 1;
-    }
-
     /**
-     * Parse the content of the given URL as a provider-configuration file.
-     *
-     * @param  service
-     *         The service type for which providers are being sought;
-     *         used to construct error detail strings
-     *
-     * @param  u
-     *         The URL naming the configuration file to be parsed
-     *
-     * @return A (possibly empty) iterator that will yield the provider-class
-     *         names in the given configuration file that are not yet members
-     *         of the returned set
+     * Uses Class.forName to load a provider class in a module.
      *
      * @throws ServiceConfigurationError
-     *         If an I/O error occurs while reading from the given URL, or
-     *         if a configuration-file format error is detected
-     *
+     *         If the class cannot be loaded
      */
-    private Iterator<String> parse(Class<?> service, URL u)
-        throws ServiceConfigurationError
-    {
-        ArrayList<String> names = new ArrayList<>();
-        try {
-            URLConnection uc = u.openConnection();
-            uc.setUseCaches(false);
-            try (InputStream in = uc.getInputStream();
-                 BufferedReader r
-                     = new BufferedReader(new InputStreamReader(in, "utf-8")))
-            {
-                int lc = 1;
-                while ((lc = parseLine(service, u, r, lc, names)) >= 0);
+    private Class<?> loadProviderInModule(Module module, String cn) {
+        Class<?> clazz = null;
+        if (acc == null) {
+            try {
+                clazz = Class.forName(module, cn);
+            } catch (LinkageError e) {
+                fail(service, "Unable to load " + cn, e);
             }
-        } catch (IOException x) {
-            fail(service, "Error accessing configuration file", x);
+        } else {
+            PrivilegedExceptionAction<Class<?>> pa = () -> Class.forName(module, cn);
+            try {
+                clazz = AccessController.doPrivileged(pa);
+            } catch (PrivilegedActionException pae) {
+                Throwable x = pae.getCause();
+                fail(service, "Unable to load " + cn, x);
+                return null;
+            }
         }
-        return names.iterator();
+        if (clazz == null)
+            fail(service, "Provider " + cn  + " not found");
+        return clazz;
     }
 
     /**
-     * Returns the {@code Constructor} to instantiate the service provider.
-     * The constructor has its accessible flag set so that the access check
-     * is suppressed when instantiating the provider. This is necessary
-     * because newInstance is a caller sensitive method and ServiceLoader
-     * is instantiating the service provider on behalf of the service
-     * consumer.
+     * A Provider implementation that supports invoking, with reduced
+     * permissions, the static factory to obtain the provider or the
+     * provider's no-arg constructor.
      */
-    private static Constructor<?> checkAndGetConstructor(Class<?> c)
-        throws NoSuchMethodException, IllegalAccessException
-    {
-        Constructor<?> ctor = c.getConstructor();
+    private final static class ProviderImpl<S> implements Provider<S> {
+        final Class<S> service;
+        final AccessControlContext acc;
+
+        final Method factoryMethod;  // factory method or null
+        final Class<? extends S> type;
+        final Constructor<? extends S> ctor; // public no-args constructor or null
+
+        /**
+         * Creates a Provider.
+         *
+         * @param service
+         *        The service type
+         * @param clazz
+         *        The provider (or provider factory) class
+         * @param acc
+         *        The access control context when running with security manager
+         *
+         * @throws ServiceConfigurationError
+         *         If the class is not public; If the class defines a public
+         *         static provider() method with a return type that is assignable
+         *         to the service type or the class is not a provider class with
+         *         a public no-args constructor.
+         */
+        @SuppressWarnings("unchecked")
+        ProviderImpl(Class<?> service, Class<?> clazz, AccessControlContext acc) {
+            this.service = (Class<S>) service;
+            this.acc = acc;
 
-        // check class and no-arg constructor are public
-        int modifiers = ctor.getModifiers();
-        if (!Modifier.isPublic(Reflection.getClassAccessFlags(c) & modifiers)) {
-            String cn = c.getName();
-            throw new IllegalAccessException(cn + " is not public");
+            int mods = clazz.getModifiers();
+            if (!Modifier.isPublic(mods)) {
+                fail(service, clazz + " is not public");
+            }
+
+            // if the class is in an explicit module then see if it is
+            // a provider factory class
+            Method factoryMethod = null;
+            if (inExplicitModule(clazz)) {
+                factoryMethod = findStaticProviderMethod(clazz);
+                if (factoryMethod != null) {
+                    Class<?> returnType = factoryMethod.getReturnType();
+                    if (!service.isAssignableFrom(returnType)) {
+                        fail(service, factoryMethod + " return type not a subtype");
+                    }
+                }
+            }
+            this.factoryMethod = factoryMethod;
+
+            if (factoryMethod == null) {
+                // no factory method so must have a public no-args constructor
+                if (!service.isAssignableFrom(clazz)) {
+                    fail(service, clazz.getName() + " not a subtype");
+                }
+                this.type = (Class<? extends S>) clazz;
+                this.ctor = (Constructor<? extends S>) getConstructor(clazz);
+            } else {
+                this.type = (Class<? extends S>) factoryMethod.getReturnType();
+                this.ctor = null;
+            }
         }
 
-        // return Constructor to create the service implementation
-        PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
-            public Void run() { ctor.setAccessible(true); return null; }
-        };
-        AccessController.doPrivileged(action);
-        return ctor;
-    }
-
-    /**
-     * Uses Class.forName to load a class in a module.
-     */
-    private static Class<?> loadClassInModule(Module module, String cn) {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm == null) {
-            return Class.forName(module, cn);
-        } else {
-            PrivilegedAction<Class<?>> pa = () -> Class.forName(module, cn);
-            return AccessController.doPrivileged(pa);
+        @Override
+        public Class<? extends S> type() {
+            return type;
         }
-    }
 
-    /**
-     * An Iterator that runs the next and hasNext methods with permissions
-     * restricted by the {@code AccessControlContext} obtained when the
-     * ServiceLoader was created.
-     */
-    private abstract class RestrictedIterator<S>
-        implements Iterator<S>
-    {
-        /**
-         * Returns {@code true} if the iteration has more elements.
-         */
-        abstract boolean hasNextService();
-
-        /**
-         * Returns the next element in the iteration
-         */
-        abstract S nextService();
-
-        public final boolean hasNext() {
-            if (acc == null) {
-                return hasNextService();
+        @Override
+        public S get() {
+            if (factoryMethod != null) {
+                return invokeFactoryMethod();
             } else {
-                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
-                    public Boolean run() { return hasNextService(); }
-                };
-                return AccessController.doPrivileged(action, acc);
+                return newInstance();
             }
         }
 
-        public final S next() {
+        /**
+         * Returns {@code true} if the provider is in an explicit module
+         */
+        private boolean inExplicitModule(Class<?> clazz) {
+            Module module = clazz.getModule();
+            return module.isNamed() && !module.getDescriptor().isAutomatic();
+        }
+
+        /**
+         * Returns the public static provider method if found.
+         *
+         * @throws ServiceConfigurationError if there is an error finding the
+         *         provider method
+         */
+        private Method findStaticProviderMethod(Class<?> clazz) {
+            Method method = null;
+            try {
+                method = LANG_ACCESS.getMethodOrNull(clazz, "provider");
+            } catch (Throwable x) {
+                fail(service, "Unable to get public provider() method", x);
+            }
+            if (method != null) {
+                int mods = method.getModifiers();
+                if (Modifier.isStatic(mods)) {
+                    assert Modifier.isPublic(mods);
+                    Method m = method;
+                    PrivilegedAction<Void> pa = () -> {
+                        m.setAccessible(true);
+                        return null;
+                    };
+                    AccessController.doPrivileged(pa);
+                    return method;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Returns the public no-arg constructor of a class.
+         *
+         * @throws ServiceConfigurationError if the class does not have
+         *         public no-arg constructor
+         */
+        private Constructor<?> getConstructor(Class<?> clazz) {
+            PrivilegedExceptionAction<Constructor<?>> pa
+                = new PrivilegedExceptionAction<>() {
+                    @Override
+                    public Constructor<?> run() throws Exception {
+                        Constructor<?> ctor = clazz.getConstructor();
+                        if (inExplicitModule(clazz))
+                            ctor.setAccessible(true);
+                        return ctor;
+                    }
+                };
+            Constructor<?> ctor = null;
+            try {
+                ctor = AccessController.doPrivileged(pa);
+            } catch (Throwable x) {
+                if (x instanceof PrivilegedActionException)
+                    x = x.getCause();
+                String cn = clazz.getName();
+                fail(service, cn + " Unable to get public no-arg constructor", x);
+            }
+            return ctor;
+        }
+
+        /**
+         * Invokes the provider's "provider" method to instantiate a provider.
+         * When running with a security manager then the method runs with
+         * permissions that are restricted by the security context of whatever
+         * created this loader.
+         */
+        private S invokeFactoryMethod() {
+            Object result = null;
+            Throwable exc = null;
             if (acc == null) {
-                return nextService();
+                try {
+                    result = factoryMethod.invoke(null);
+                } catch (Throwable x) {
+                    exc = x;
+                }
             } else {
-                PrivilegedAction<S> action = new PrivilegedAction<S>() {
-                    public S run() { return nextService(); }
+                PrivilegedExceptionAction<?> pa = new PrivilegedExceptionAction<>() {
+                    @Override
+                    public Object run() throws Exception {
+                        return factoryMethod.invoke(null);
+                    }
                 };
-                return AccessController.doPrivileged(action, acc);
+                // invoke factory method with permissions restricted by acc
+                try {
+                    result = AccessController.doPrivileged(pa, acc);
+                } catch (PrivilegedActionException pae) {
+                    exc = pae.getCause();
+                }
+            }
+            if (exc != null) {
+                if (exc instanceof InvocationTargetException)
+                    exc = exc.getCause();
+                fail(service, factoryMethod + " failed", exc);
+            }
+            if (result == null) {
+                fail(service, factoryMethod + " returned null");
             }
+            @SuppressWarnings("unchecked")
+            S p = (S) result;
+            return p;
+        }
+
+        /**
+         * Invokes Constructor::newInstance to instantiate a provider. When running
+         * with a security manager then the constructor runs with permissions that
+         * are restricted by the security context of whatever created this loader.
+         */
+        private S newInstance() {
+            S p = null;
+            Throwable exc = null;
+            if (acc == null) {
+                try {
+                    p = ctor.newInstance();
+                } catch (Throwable x) {
+                    exc = x;
+                }
+            } else {
+                PrivilegedExceptionAction<S> pa = new PrivilegedExceptionAction<>() {
+                    @Override
+                    public S run() throws Exception {
+                        return ctor.newInstance();
+                    }
+                };
+                // invoke constructor with permissions restricted by acc
+                try {
+                    p = AccessController.doPrivileged(pa, acc);
+                } catch (PrivilegedActionException pae) {
+                    exc = pae.getCause();
+                }
+            }
+            if (exc != null) {
+                if (exc instanceof InvocationTargetException)
+                    exc = exc.getCause();
+                String cn = ctor.getDeclaringClass().getName();
+                fail(service,
+                     "Provider " + cn + " could not be instantiated", exc);
+            }
+            return p;
+        }
+
+        // For now, equals/hashCode uses the access control context to ensure
+        // that two Providers created with different contexts are not equal
+        // when running with a security manager.
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type, acc);
+        }
+
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof ProviderImpl))
+                return false;
+            @SuppressWarnings("unchecked")
+            ProviderImpl<?> that = (ProviderImpl<?>)ob;
+            return this.type == that.type
+                    && Objects.equals(this.acc, that.acc);
         }
     }
 
     /**
      * Implements lazy service provider lookup of service providers that
-     * are provided by modules in a module Layer.
+     * are provided by modules in a module Layer (or parent layers)
      */
-    private class LayerLookupIterator
-        extends RestrictedIterator<S>
+    private final class LayerLookupIterator<T>
+        implements Iterator<Provider<T>>
     {
-        final String serviceName;
-        Layer currentLayer;
+        Deque<Layer> stack = new ArrayDeque<>();
+        Set<Layer> visited = new HashSet<>();
         Iterator<ServiceProvider> iterator;
-        ServiceProvider nextProvider;
+        ServiceProvider next;  // next provider to load
 
         LayerLookupIterator() {
-            serviceName = service.getName();
-            currentLayer = layer;
-
-            // need to get us started
-            iterator = providers(currentLayer, serviceName);
+            visited.add(layer);
+            stack.push(layer);
         }
 
-        Iterator<ServiceProvider> providers(Layer layer, String service) {
-            ServicesCatalog catalog = SharedSecrets
-                    .getJavaLangReflectModuleAccess()
-                    .getServicesCatalog(layer);
-
+        private Iterator<ServiceProvider> providers(Layer layer) {
+            ServicesCatalog catalog = JLRM_ACCESS.getServicesCatalog(layer);
             return catalog.findServices(serviceName).iterator();
         }
 
         @Override
-        boolean hasNextService() {
-
+        public boolean hasNext() {
             // already have the next provider cached
-            if (nextProvider != null)
+            if (next != null)
                 return true;
 
             while (true) {
 
-                // next provider
+                // next provider (or provider factory)
                 if (iterator != null && iterator.hasNext()) {
-                    nextProvider = iterator.next();
+                    next = iterator.next();
                     return true;
                 }
 
-                // next layer
-                Layer parent = currentLayer.parent().orElse(null);
-                if (parent == null)
+                // next layer (DFS order)
+                if (stack.isEmpty())
                     return false;
 
-                currentLayer = parent;
-                iterator = providers(currentLayer, serviceName);
+                Layer layer = stack.pop();
+                List<Layer> parents = layer.parents();
+                for (int i = parents.size() - 1; i >= 0; i--) {
+                    Layer parent = parents.get(i);
+                    if (!visited.contains(parent)) {
+                        visited.add(parent);
+                        stack.push(parent);
+                    }
+                }
+                iterator = providers(layer);
             }
         }
 
         @Override
-        S nextService() {
-            if (!hasNextService())
+        public Provider<T> next() {
+            if (!hasNext())
                 throw new NoSuchElementException();
 
-            ServiceProvider provider = nextProvider;
-            nextProvider = null;
+            // take next provider
+            ServiceProvider provider = next;
+            next = null;
 
+            // attempt to load provider
             Module module = provider.module();
             String cn = provider.providerName();
-
-            // attempt to load the provider
-            Class<?> c = loadClassInModule(module, cn);
-            if (c == null)
-                fail(service, "Provider " + cn  + " not found");
-            if (!service.isAssignableFrom(c))
-                fail(service, "Provider " + cn  + " not a subtype");
-
-            // instantiate the provider
-            S p = null;
-            try {
-                Constructor<?> ctor = checkAndGetConstructor(c);
-                p = service.cast(ctor.newInstance());
-            } catch (Throwable x) {
-                if (x instanceof InvocationTargetException)
-                    x = x.getCause();
-                fail(service,
-                        "Provider " + cn + " could not be instantiated", x);
-            }
-
-            // add to cached provider list
-            providers.add(p);
-
-            return p;
+            Class<?> clazz = loadProviderInModule(module, cn);
+            return new ProviderImpl<T>(service, clazz, acc);
         }
     }
 
     /**
      * Implements lazy service provider lookup of service providers that
-     * are provided by modules defined to a class loader.
+     * are provided by modules defined to a class loader or to modules in
+     * layers with a module defined to the class loader.
      */
-    private class ModuleServicesIterator
-        extends RestrictedIterator<S>
+    private final class ModuleServicesLookupIterator<T>
+        implements Iterator<Provider<T>>
     {
-        final JavaLangAccess langAccess = SharedSecrets.getJavaLangAccess();
-
         ClassLoader currentLoader;
         Iterator<ServiceProvider> iterator;
-        ServiceProvider nextProvider;
+        ServiceProvider next;  // next provider to load
 
-        ModuleServicesIterator() {
+        ModuleServicesLookupIterator() {
             this.currentLoader = loader;
             this.iterator = iteratorFor(loader);
         }
 
         /**
+         * Returns iterator to iterate over the implementations of {@code
+         * service} in the given layer.
+         */
+        private List<ServiceProvider> providers(Layer layer) {
+            ServicesCatalog catalog = JLRM_ACCESS.getServicesCatalog(layer);
+            return catalog.findServices(serviceName);
+        }
+
+        /**
          * Returns an iterator to iterate over the implementations of {@code
-         * service} in modules defined to the given class loader.
+         * service} in modules defined to the given class loader or in custom
+         * layers with a module defined to this class loader.
          */
         private Iterator<ServiceProvider> iteratorFor(ClassLoader loader) {
 
-            // if the class loader is in a loader pool then return an Iterator
-            // that iterates over all service providers in the pool that provide
-            // an implementation of the service
-            if (currentLoader instanceof Loader) {
-                LoaderPool pool = ((Loader) loader).pool();
-                if (pool != null) {
-                    return pool.loaders()
-                            .map(l -> langAccess.getServicesCatalog(l))
-                            .filter(sc -> sc != null)
-                            .map(sc -> sc.findServices(service.getName()))
-                            .flatMap(Set::stream)
-                            .iterator();
-                }
+            // modules defined to this class loader
+            ServicesCatalog catalog;
+            if (loader == null) {
+                catalog = BootLoader.getServicesCatalog();
+            } else {
+                catalog = ServicesCatalog.getServicesCatalogOrNull(loader);
+            }
+            Stream<ServiceProvider> stream1;
+            if (catalog == null) {
+                stream1 = Stream.empty();
+            } else {
+                stream1 = catalog.findServices(serviceName).stream();
             }
 
-            ServicesCatalog catalog;
-            if (currentLoader == null) {
-                catalog = BootLoader.getServicesCatalog();
+            // modules in custom layers that define modules to the class loader
+            Stream<ServiceProvider> stream2;
+            if (loader == null) {
+                stream2 = Stream.empty();
             } else {
-                catalog = langAccess.getServicesCatalog(currentLoader);
+                Layer bootLayer = Layer.boot();
+                stream2 = JLRM_ACCESS.layers(loader)
+                        .filter(l -> (l != bootLayer))
+                        .map(l -> providers(l))
+                        .flatMap(List::stream);
             }
-            if (catalog == null) {
-                return Collections.emptyIterator();
-            } else {
-                return catalog.findServices(service.getName()).iterator();
-            }
+
+            return Stream.concat(stream1, stream2).iterator();
         }
 
         @Override
-        boolean hasNextService() {
+        public boolean hasNext() {
             // already have the next provider cached
-            if (nextProvider != null)
+            if (next != null)
                 return true;
 
             while (true) {
                 if (iterator.hasNext()) {
-                    nextProvider = iterator.next();
+                    next = iterator.next();
                     return true;
                 }
 
@@ -710,138 +972,220 @@
         }
 
         @Override
-        S nextService() {
-            if (!hasNextService())
+        public Provider<T> next() {
+            if (!hasNext())
                 throw new NoSuchElementException();
 
-            ServiceProvider provider = nextProvider;
-            nextProvider = null;
+            // take next provider
+            ServiceProvider provider = next;
+            next = null;
 
-            // attempt to load the provider
+            // attempt to load provider
             Module module = provider.module();
             String cn = provider.providerName();
-
-            Class<?> c = loadClassInModule(module, cn);
-            if (c == null) {
-                fail(service,
-                    "Provider " + cn + " not found in " + module.getName());
-            }
-            if (!service.isAssignableFrom(c)) {
-                fail(service, "Provider " + cn  + " not a subtype");
-            }
-
-            // instantiate the provider
-            S p = null;
-            try {
-                Constructor<?> ctor = checkAndGetConstructor(c);
-                p = service.cast(ctor.newInstance());
-            } catch (Throwable x) {
-                if (x instanceof InvocationTargetException)
-                    x = x.getCause();
-                fail(service,
-                    "Provider " + cn + " could not be instantiated", x);
-            }
-
-            // add to provider list
-            providers.add(p);
-
-            // record the class name of the service provider, this is
-            // needed for cases where there a module has both a "uses"
-            // and a services configuration file listing the same
-            // provider
-            providerNames.add(cn);
-
-            return p;
+            Class<?> clazz = loadProviderInModule(module, cn);
+            return new ProviderImpl<T>(service, clazz, acc);
         }
     }
 
     /**
-     * Implements lazy service provider lookup where the service providers
-     * are configured via service configuration files.
+     * Implements lazy service provider lookup where the service providers are
+     * configured via service configuration files. Service providers in named
+     * modules are silently ignored by this lookup iterator.
      */
-    private class LazyClassPathIterator
-        extends RestrictedIterator<S>
+    private final class LazyClassPathLookupIterator<T>
+        implements Iterator<Provider<T>>
     {
+        static final String PREFIX = "META-INF/services/";
+
         Enumeration<URL> configs;
         Iterator<String> pending;
-        String nextName;
+        Class<?> nextClass;
+        String nextErrorMessage;  // when hasNext fails with CNFE
+
+        LazyClassPathLookupIterator() { }
 
-        @Override
-        boolean hasNextService() {
-            if (nextName != null) {
+        /**
+         * Parse a single line from the given configuration file, adding the
+         * name on the line to the names list.
+         */
+        private int parseLine(URL u, BufferedReader r, int lc, Set<String> names)
+            throws IOException
+        {
+            String ln = r.readLine();
+            if (ln == null) {
+                return -1;
+            }
+            int ci = ln.indexOf('#');
+            if (ci >= 0) ln = ln.substring(0, ci);
+            ln = ln.trim();
+            int n = ln.length();
+            if (n != 0) {
+                if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
+                    fail(service, u, lc, "Illegal configuration-file syntax");
+                int cp = ln.codePointAt(0);
+                if (!Character.isJavaIdentifierStart(cp))
+                    fail(service, u, lc, "Illegal provider-class name: " + ln);
+                int start = Character.charCount(cp);
+                for (int i = start; i < n; i += Character.charCount(cp)) {
+                    cp = ln.codePointAt(i);
+                    if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
+                        fail(service, u, lc, "Illegal provider-class name: " + ln);
+                }
+                names.add(ln);
+            }
+            return lc + 1;
+        }
+
+        /**
+         * Parse the content of the given URL as a provider-configuration file.
+         */
+        private Iterator<String> parse(URL u) {
+            Set<String> names = new LinkedHashSet<>(); // preserve insertion order
+            try {
+                URLConnection uc = u.openConnection();
+                uc.setUseCaches(false);
+                try (InputStream in = uc.getInputStream();
+                     BufferedReader r
+                         = new BufferedReader(new InputStreamReader(in, "utf-8")))
+                {
+                    int lc = 1;
+                    while ((lc = parseLine(u, r, lc, names)) >= 0);
+                }
+            } catch (IOException x) {
+                fail(service, "Error accessing configuration file", x);
+            }
+            return names.iterator();
+        }
+
+        private boolean hasNextService() {
+            if (nextClass != null || nextErrorMessage != null) {
                 return true;
             }
-            if (configs == null) {
+
+            Class<?> clazz = null;
+            do {
+                if (configs == null) {
+                    try {
+                        String fullName = PREFIX + service.getName();
+                        if (loader == null)
+                            configs = ClassLoader.getSystemResources(fullName);
+                        else
+                            configs = loader.getResources(fullName);
+                    } catch (IOException x) {
+                        fail(service, "Error locating configuration files", x);
+                    }
+                }
+                while ((pending == null) || !pending.hasNext()) {
+                    if (!configs.hasMoreElements()) {
+                        return false;
+                    }
+                    pending = parse(configs.nextElement());
+                }
+                String cn = pending.next();
                 try {
-                    String fullName = PREFIX + service.getName();
-                    if (loader == null)
-                        configs = ClassLoader.getSystemResources(fullName);
-                    else
-                        configs = loader.getResources(fullName);
-                } catch (IOException x) {
-                    fail(service, "Error locating configuration files", x);
+                    clazz = Class.forName(cn, false, loader);
+                } catch (ClassNotFoundException x) {
+                    // don't throw SCE here to long standing behavior
+                    nextErrorMessage = "Provider " + cn + " not found";
+                    return true;
                 }
-            }
-            while ((pending == null) || !pending.hasNext()) {
-                if (!configs.hasMoreElements()) {
-                    return false;
-                }
-                pending = parse(service, configs.nextElement());
-            }
-            nextName = pending.next();
+
+            } while (clazz.getModule().isNamed()); // ignore if in named module
+
+            nextClass = clazz;
             return true;
         }
 
-        @Override
-        S nextService() {
+        private Provider<T> nextService() {
             if (!hasNextService())
                 throw new NoSuchElementException();
-            String cn = nextName;
-            nextName = null;
-            Class<?> c = null;
-            try {
-                c = Class.forName(cn, false, loader);
-            } catch (ClassNotFoundException x) {
-                fail(service,
-                     "Provider " + cn + " not found");
-            }
-            if (!service.isAssignableFrom(c)) {
-                fail(service,
-                     "Provider " + cn  + " not a subtype");
+
+            // throw any SCE with error recorded by hasNext
+            if (nextErrorMessage != null) {
+                String msg = nextErrorMessage;
+                nextErrorMessage = null;
+                fail(service, msg);
             }
-            S p = null;
-            try {
-                @SuppressWarnings("deprecation")
-                Object tmp = c.newInstance();
-                p = service.cast(tmp);
-            } catch (Throwable x) {
-                fail(service,
-                     "Provider " + cn + " could not be instantiated",
-                     x);
+
+            // return next provider
+            Class<?> clazz = nextClass;
+            nextClass = null;
+            return new ProviderImpl<T>(service, clazz, acc);
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (acc == null) {
+                return hasNextService();
+            } else {
+                PrivilegedAction<Boolean> action = new PrivilegedAction<>() {
+                    public Boolean run() { return hasNextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
             }
-            providers.add(p);
-            providerNames.add(cn);
-            return p;
+        }
+
+        @Override
+        public Provider<T> next() {
+            if (acc == null) {
+                return nextService();
+            } else {
+                PrivilegedAction<Provider<T>> action = new PrivilegedAction<>() {
+                    public Provider<T> run() { return nextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
         }
     }
 
     /**
-     * Lazily loads the available providers of this loader's service.
+     * Returns a new lookup iterator.
+     */
+    private Iterator<Provider<S>> newLookupIterator() {
+        assert layer == null || loader == null;
+        if (layer != null) {
+            return new LayerLookupIterator<>();
+        } else {
+            Iterator<Provider<S>> first = new ModuleServicesLookupIterator<>();
+            Iterator<Provider<S>> second = new LazyClassPathLookupIterator<>();
+            return new Iterator<Provider<S>>() {
+                @Override
+                public boolean hasNext() {
+                    return (first.hasNext() || second.hasNext());
+                }
+                @Override
+                public Provider<S> next() {
+                    if (first.hasNext()) {
+                        return first.next();
+                    } else if (second.hasNext()) {
+                        return second.next();
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+    }
+
+    /**
+     * Lazily load and instantiate the available providers of this loader's
+     * service.
      *
      * <p> The iterator returned by this method first yields all of the
-     * elements of the provider cache, in instantiation order.  It then lazily
-     * loads and instantiates any remaining providers, adding each one to the
-     * cache in turn.
+     * elements of the provider cache, in the order that they were loaded.
+     * It then lazily loads and instantiates any remaining providers,
+     * adding each one to the cache in turn.
      *
      * <p> To achieve laziness the actual work of locating and instantiating
      * providers must be done by the iterator itself. Its {@link
      * java.util.Iterator#hasNext hasNext} and {@link java.util.Iterator#next
      * next} methods can therefore throw a {@link ServiceConfigurationError}
-     * if a provider class cannot be loaded, doesn't have the appropriate
-     * constructor, can't be assigned to the service type or if any other kind
-     * of exception or error is thrown as the next provider is located and
-     * instantiated. To write robust code it is only necessary to catch {@link
-     * ServiceConfigurationError} when using a service iterator.
+     * if a provider class cannot be loaded, doesn't have an appropriate static
+     * factory method or constructor, can't be assigned to the service type or
+     * if any other kind of exception or error is thrown as the next provider
+     * is located and instantiated. To write robust code it is only necessary
+     * to catch {@link ServiceConfigurationError} when using a service iterator.
      *
      * <p> If such an error is thrown then subsequent invocations of the
      * iterator will make a best effort to locate and instantiate the next
@@ -856,7 +1200,7 @@
      * preferable to throw an error rather than try to recover or, even worse,
      * fail silently.</blockquote>
      *
-     * <p> If this loader's provider cache is cleared by invoking the {@link
+     * <p> If this loader's provider caches are cleared by invoking the {@link
      * #reload() reload} method then existing iterators for this service
      * loader should be discarded.
      * The {@link java.util.Iterator#hasNext() hasNext} and {@link
@@ -868,16 +1212,16 @@
      * Invoking its {@link java.util.Iterator#remove() remove} method will
      * cause an {@link UnsupportedOperationException} to be thrown.
      *
-     * @implNote When adding providers to the cache, the {@link #iterator
-     * Iterator} processes resources in the order that the {@link
-     * java.lang.ClassLoader#getResources(java.lang.String)
-     * ClassLoader.getResources(String)} method finds the service configuration
-     * files.
-     *
      * @return  An iterator that lazily loads providers for this loader's
      *          service
      */
     public Iterator<S> iterator() {
+
+        // create lookup iterator if needed
+        if (lookupIterator1 == null) {
+            lookupIterator1 = newLookupIterator();
+        }
+
         return new Iterator<S>() {
 
             // record reload count
@@ -895,34 +1239,23 @@
                     throw new ConcurrentModificationException();
             }
 
+            @Override
             public boolean hasNext() {
                 checkReloadCount();
-                if (index < providers.size())
+                if (index < instantiatedProviders.size())
                     return true;
-
-                if (layerLookupIterator != null) {
-                    return layerLookupIterator.hasNext();
-                } else {
-                    return moduleServicesIterator.hasNext() ||
-                            lazyClassPathIterator.hasNext();
-                }
+                return lookupIterator1.hasNext();
             }
 
+            @Override
             public S next() {
                 checkReloadCount();
                 S next;
-                if (index < providers.size()) {
-                    next = providers.get(index);
+                if (index < instantiatedProviders.size()) {
+                    next = instantiatedProviders.get(index);
                 } else {
-                    if (layerLookupIterator != null) {
-                        next = layerLookupIterator.next();
-                    } else {
-                        if (moduleServicesIterator.hasNext()) {
-                            next = moduleServicesIterator.next();
-                        } else {
-                            next = lazyClassPathIterator.next();
-                        }
-                    }
+                    next = lookupIterator1.next().get();
+                    instantiatedProviders.add(next);
                 }
                 index++;
                 return next;
@@ -932,6 +1265,108 @@
     }
 
     /**
+     * Returns a stream that lazily loads the available providers of this
+     * loader's service. The stream elements are of type {@link Provider
+     * Provider}, the {@code Provider}'s {@link Provider#get() get} method
+     * must be invoked to get or instantiate the provider.
+     *
+     * <p> When processing the stream then providers that were previously
+     * loaded by stream operations are processed first, in load order. It then
+     * lazily loads any remaining providers. If a provider class cannot be
+     * loaded, can't be assigned to the service type, or some other error is
+     * thrown when locating the provider then it is wrapped with a {@code
+     * ServiceConfigurationError} and thrown by whatever method caused the
+     * provider to be loaded. </p>
+     *
+     * <p> If this loader's provider caches are cleared by invoking the {@link
+     * #reload() reload} method then existing streams for this service
+     * loader should be discarded. </p>
+     *
+     * <p> The following examples demonstrate usage. The first example
+     * creates a stream of providers, the second example is the same except
+     * that it sorts the providers by provider class name (and so locate all
+     * providers).
+     * <pre>{@code
+     *    Stream<CodecSet> providers = ServiceLoader.load(CodecSet.class)
+     *            .stream()
+     *            .map(Provider::get);
+     *
+     *    Stream<CodecSet> providers = ServiceLoader.load(CodecSet.class)
+     *            .stream()
+     *            .sorted(Comparator.comparing(p -> p.type().getName()))
+     *            .map(Provider::get);
+     * }</pre>
+     *
+     * @return  A stream that lazily loads providers for this loader's service
+     *
+     * @since 9
+     */
+    public Stream<Provider<S>> stream() {
+        // use cached providers as the source when all providers loaded
+        if (loadedAllProviders) {
+            return loadedProviders.stream();
+        }
+
+        // create lookup iterator if needed
+        if (lookupIterator2 == null) {
+            lookupIterator2 = newLookupIterator();
+        }
+
+        // use lookup iterator and cached providers as source
+        Spliterator<Provider<S>> s = new ProviderSpliterator<>(lookupIterator2);
+        return StreamSupport.stream(s, false);
+    }
+
+    private class ProviderSpliterator<T> implements Spliterator<Provider<T>> {
+        final int expectedReloadCount = ServiceLoader.this.reloadCount;
+        final Iterator<Provider<T>> iterator;
+        int index;
+
+        ProviderSpliterator(Iterator<Provider<T>> iterator) {
+            this.iterator = iterator;
+        }
+
+        @Override
+        public Spliterator<Provider<T>> trySplit() {
+            return null;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super Provider<T>> action) {
+            if (ServiceLoader.this.reloadCount != expectedReloadCount)
+                throw new ConcurrentModificationException();
+            Provider<T> next = null;
+            if (index < loadedProviders.size()) {
+                next = (Provider<T>) loadedProviders.get(index++);
+            } else if (iterator.hasNext()) {
+                next = iterator.next();
+            } else {
+                loadedAllProviders = true;
+            }
+            if (next != null) {
+                action.accept(next);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public int characteristics() {
+            // not IMMUTABLE as structural interference possible
+            // not NOTNULL so that the characteristics are a subset of the
+            // characteristics when all Providers have been located.
+            return Spliterator.ORDERED;
+        }
+
+        @Override
+        public long estimateSize() {
+            return Long.MAX_VALUE;
+        }
+    }
+
+    /**
      * Creates a new service loader for the given service type, class
      * loader, and caller.
      *
@@ -977,7 +1412,7 @@
      *
      * @throws ServiceConfigurationError
      *         if the service type is not accessible to the caller or the
-     *         caller is in a named module and its module descriptor does
+     *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
      */
     @CallerSensitive
@@ -993,15 +1428,23 @@
      * context class loader}.
      *
      * <p> An invocation of this convenience method of the form
-     *
-     * <blockquote><pre>
-     * ServiceLoader.load(<i>service</i>)</pre></blockquote>
+     * <pre>{@code
+     * ServiceLoader.load(service)
+     * }</pre>
      *
      * is equivalent to
      *
-     * <blockquote><pre>
-     * ServiceLoader.load(<i>service</i>,
-     *                    Thread.currentThread().getContextClassLoader())</pre></blockquote>
+     * <pre>{@code
+     * ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
+     * }</pre>
+     *
+     * @apiNote Service loader objects obtained with this method should not be
+     * cached VM-wide. For example, different applications in the same VM may
+     * have different thread context class loaders. A lookup by one application
+     * may locate a service provider that is only visible via its thread
+     * context class loader and so is not suitable to be located by the other
+     * application. Memory leaks can also arise. A thread local may be suited
+     * to some applications.
      *
      * @param  <S> the class of the service type
      *
@@ -1012,7 +1455,7 @@
      *
      * @throws ServiceConfigurationError
      *         if the service type is not accessible to the caller or the
-     *         caller is in a named module and its module descriptor does
+     *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
      */
     @CallerSensitive
@@ -1027,9 +1470,9 @@
      *
      * <p> This convenience method is equivalent to: </p>
      *
-     * <blockquote><pre>
-     * ServiceLoader.load(<i>service</i>, <i>ClassLoader.getPlatformClassLoader())</i>
-     * </pre></blockquote>
+     * <pre>{@code
+     * ServiceLoader.load(service, ClassLoader.getPlatformClassLoader())
+     * }</pre>
      *
      * <p> This method is intended for use when only installed providers are
      * desired.  The resulting service will only find and load providers that
@@ -1045,18 +1488,13 @@
      *
      * @throws ServiceConfigurationError
      *         if the service type is not accessible to the caller or the
-     *         caller is in a named module and its module descriptor does
+     *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
      */
     @CallerSensitive
     public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
-        ClassLoader cl = ClassLoader.getSystemClassLoader();
-        ClassLoader prev = null;
-        while (cl != null) {
-            prev = cl;
-            cl = cl.getParent();
-        }
-        return new ServiceLoader<>(Reflection.getCallerClass(), service, prev);
+        ClassLoader cl = ClassLoader.getPlatformClassLoader();
+        return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
     }
 
     /**
@@ -1080,16 +1518,71 @@
      *
      * @throws ServiceConfigurationError
      *         if the service type is not accessible to the caller or the
-     *         caller is in a named module and its module descriptor does
+     *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
      *
      * @since 9
      */
     @CallerSensitive
     public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
-        return new ServiceLoader<>(Reflection.getCallerClass(),
-                                   Objects.requireNonNull(layer),
-                                   Objects.requireNonNull(service));
+        return new ServiceLoader<>(Reflection.getCallerClass(), layer, service);
+    }
+
+    /**
+     * Load the first available provider of this loader's service. This
+     * convenience method is equivalent to invoking the {@link #iterator()
+     * iterator()} method and obtaining the first element. It therefore
+     * returns the first element from the provider cache if possible, it
+     * otherwise attempts to load and instantiate the first provider.
+     *
+     * <p> The following example loads the first available provider. If there
+     * are no providers deployed then it uses a default implementation.
+     * <pre>{@code
+     *    CodecSet provider =
+     *        ServiceLoader.load(CodecSet.class).findFirst().orElse(DEFAULT_CODECSET);
+     * }</pre>
+     * @return The first provider or empty {@code Optional} if no providers
+     *         are located
+     *
+     * @throws ServiceConfigurationError
+     *         If a provider class cannot be loaded, doesn't have the
+     *         appropriate static factory method or constructor, can't be
+     *         assigned to the service type, or if any other kind of exception
+     *         or error is thrown when locating or instantiating the provider.
+     *
+     * @since 9
+     */
+    public Optional<S> findFirst() {
+        Iterator<S> iterator = iterator();
+        if (iterator.hasNext()) {
+            return Optional.of(iterator.next());
+        } else {
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Clear this loader's provider cache so that all providers will be
+     * reloaded.
+     *
+     * <p> After invoking this method, subsequent invocations of the {@link
+     * #iterator() iterator} or {@link #stream() stream} methods will lazily
+     * look up providers (and instantiate in the case of {@code iterator})
+     * from scratch, just as is done by a newly-created loader.
+     *
+     * <p> This method is intended for use in situations in which new providers
+     * can be installed into a running Java virtual machine.
+     */
+    public void reload() {
+        lookupIterator1 = null;
+        instantiatedProviders.clear();
+
+        lookupIterator2 = null;
+        loadedProviders.clear();
+        loadedAllProviders = false;
+
+        // increment count to allow CME be thrown
+        reloadCount++;
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/Vector.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/Vector.java	Wed Jul 05 22:32:06 2017 +0200
@@ -513,7 +513,7 @@
      * Returns the last component of the vector.
      *
      * @return  the last component of the vector, i.e., the component at index
-     *          <code>size()&nbsp;-&nbsp;1</code>.
+     *          {@code size() - 1}
      * @throws NoSuchElementException if this vector is empty
      */
     public synchronized E lastElement() {
@@ -675,10 +675,7 @@
      * method (which is part of the {@link List} interface).
      */
     public synchronized void removeAllElements() {
-        // Let gc do its work
-        for (int i = 0; i < elementCount; i++)
-            elementData[i] = null;
-
+        Arrays.fill(elementData, 0, elementCount, null);
         modCount++;
         elementCount = 0;
     }
@@ -693,7 +690,7 @@
     public synchronized Object clone() {
         try {
             @SuppressWarnings("unchecked")
-                Vector<E> v = (Vector<E>) super.clone();
+            Vector<E> v = (Vector<E>) super.clone();
             v.elementData = Arrays.copyOf(elementData, elementCount);
             v.modCount = 0;
             return v;
@@ -759,6 +756,11 @@
         return (E) elementData[index];
     }
 
+    @SuppressWarnings("unchecked")
+    static <E> E elementAt(Object[] es, int index) {
+        return (E) es[index];
+    }
+
     /**
      * Returns the element at the specified position in this Vector.
      *
@@ -855,10 +857,10 @@
      * Shifts any subsequent elements to the left (subtracts one from their
      * indices).  Returns the element that was removed from the Vector.
      *
+     * @param index the index of the element to be removed
+     * @return element that was removed
      * @throws ArrayIndexOutOfBoundsException if the index is out of range
      *         ({@code index < 0 || index >= size()})
-     * @param index the index of the element to be removed
-     * @return element that was removed
      * @since 1.2
      */
     public synchronized E remove(int index) {
@@ -949,8 +951,9 @@
      *         or if the specified collection is null
      * @since 1.2
      */
-    public synchronized boolean removeAll(Collection<?> c) {
-        return super.removeAll(c);
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
     }
 
     /**
@@ -972,8 +975,62 @@
      *         or if the specified collection is null
      * @since 1.2
      */
-    public synchronized boolean retainAll(Collection<?> c) {
-        return super.retainAll(c);
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    @Override
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    private synchronized boolean bulkRemove(Predicate<? super E> filter) {
+        int expectedModCount = modCount;
+        final Object[] es = elementData;
+        final int end = elementCount;
+        int i;
+        // Optimize for initial run of survivors
+        for (i = 0; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        // Tolerate predicates that reentrantly access the collection for
+        // read (but writers still get CME), so traverse once to find
+        // elements to delete, a second pass to physically expunge.
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - beg);
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            expectedModCount++;
+            modCount++;
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    es[w++] = es[i];
+            Arrays.fill(es, elementCount = w, end, null);
+            return true;
+        } else {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return false;
+        }
     }
 
     /**
@@ -1095,15 +1152,12 @@
      * (If {@code toIndex==fromIndex}, this operation has no effect.)
      */
     protected synchronized void removeRange(int fromIndex, int toIndex) {
-        int numMoved = elementCount - toIndex;
-        System.arraycopy(elementData, toIndex, elementData, fromIndex,
-                         numMoved);
+        final Object[] es = elementData;
+        final int oldSize = elementCount;
+        System.arraycopy(es, toIndex, es, fromIndex, oldSize - toIndex);
 
-        // Let gc do its work
         modCount++;
-        int newElementCount = elementCount - (toIndex-fromIndex);
-        while (elementCount != newElementCount)
-            elementData[--elementCount] = null;
+        Arrays.fill(es, elementCount -= (toIndex - fromIndex), oldSize, null);
     }
 
     /**
@@ -1212,14 +1266,11 @@
                 if (i >= size) {
                     return;
                 }
-        @SuppressWarnings("unchecked")
-                final E[] elementData = (E[]) Vector.this.elementData;
-                if (i >= elementData.length) {
+                final Object[] es = elementData;
+                if (i >= es.length)
                     throw new ConcurrentModificationException();
-                }
-                while (i != size && modCount == expectedModCount) {
-                    action.accept(elementData[i++]);
-                }
+                while (i < size && modCount == expectedModCount)
+                    action.accept(elementAt(es, i++));
                 // update once at end of iteration to reduce heap write traffic
                 cursor = i;
                 lastRet = i - 1;
@@ -1290,73 +1341,24 @@
     public synchronized void forEach(Consumer<? super E> action) {
         Objects.requireNonNull(action);
         final int expectedModCount = modCount;
-        @SuppressWarnings("unchecked")
-        final E[] elementData = (E[]) this.elementData;
-        final int elementCount = this.elementCount;
-        for (int i=0; modCount == expectedModCount && i < elementCount; i++) {
-            action.accept(elementData[i]);
-        }
-        if (modCount != expectedModCount) {
+        final Object[] es = elementData;
+        final int size = elementCount;
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            action.accept(elementAt(es, i));
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
     }
 
     @Override
-    @SuppressWarnings("unchecked")
-    public synchronized boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        // figure out which elements are to be removed
-        // any exception thrown from the filter predicate at this stage
-        // will leave the collection unmodified
-        int removeCount = 0;
-        final int size = elementCount;
-        final BitSet removeSet = new BitSet(size);
-        final int expectedModCount = modCount;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            @SuppressWarnings("unchecked")
-            final E element = (E) elementData[i];
-            if (filter.test(element)) {
-                removeSet.set(i);
-                removeCount++;
-            }
-        }
-        if (modCount != expectedModCount) {
-            throw new ConcurrentModificationException();
-        }
-
-        // shift surviving elements left over the spaces left by removed elements
-        final boolean anyToRemove = removeCount > 0;
-        if (anyToRemove) {
-            final int newSize = size - removeCount;
-            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
-                i = removeSet.nextClearBit(i);
-                elementData[j] = elementData[i];
-            }
-            for (int k=newSize; k < size; k++) {
-                elementData[k] = null;  // Let gc do its work
-            }
-            elementCount = newSize;
-            if (modCount != expectedModCount) {
-                throw new ConcurrentModificationException();
-            }
-            modCount++;
-        }
-
-        return anyToRemove;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
     public synchronized void replaceAll(UnaryOperator<E> operator) {
         Objects.requireNonNull(operator);
         final int expectedModCount = modCount;
+        final Object[] es = elementData;
         final int size = elementCount;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            elementData[i] = operator.apply((E) elementData[i]);
-        }
-        if (modCount != expectedModCount) {
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
         modCount++;
     }
 
@@ -1365,9 +1367,8 @@
     public synchronized void sort(Comparator<? super E> c) {
         final int expectedModCount = modCount;
         Arrays.sort((E[]) elementData, 0, elementCount, c);
-        if (modCount != expectedModCount) {
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
         modCount++;
     }
 
@@ -1397,7 +1398,7 @@
         private int fence; // -1 until used; then one past last index
         private int expectedModCount; // initialized when fence set
 
-        /** Create new spliterator covering the given  range */
+        /** Create new spliterator covering the given range */
         VectorSpliterator(Vector<E> list, Object[] array, int origin, int fence,
                           int expectedModCount) {
             this.list = list;
@@ -1410,7 +1411,7 @@
         private int getFence() { // initialize on first use
             int hi;
             if ((hi = fence) < 0) {
-                synchronized(list) {
+                synchronized (list) {
                     array = list.elementData;
                     expectedModCount = list.modCount;
                     hi = fence = list.elementCount;
@@ -1449,7 +1450,7 @@
                 throw new NullPointerException();
             if ((lst = list) != null) {
                 if ((hi = fence) < 0) {
-                    synchronized(lst) {
+                    synchronized (lst) {
                         expectedModCount = lst.modCount;
                         a = array = lst.elementData;
                         hi = fence = lst.elementCount;
@@ -1475,4 +1476,9 @@
             return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
         }
     }
+
+    void checkInvariants() {
+        // assert elementCount >= 0;
+        // assert elementCount == elementData.length || elementData[elementCount] == null;
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java	Wed Jul 05 22:32:06 2017 +0200
@@ -46,6 +46,8 @@
 import java.util.Spliterators;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * A bounded {@linkplain BlockingQueue blocking queue} backed by an
@@ -85,6 +87,11 @@
 public class ArrayBlockingQueue<E> extends AbstractQueue<E>
         implements BlockingQueue<E>, java.io.Serializable {
 
+    /*
+     * Much of the implementation mechanics, especially the unusual
+     * nested loops, are shared and co-maintained with ArrayDeque.
+     */
+
     /**
      * Serialization ID. This class relies on default serialization
      * even for the items array, which is default-serialized, even if
@@ -129,10 +136,21 @@
     // Internal helper methods
 
     /**
-     * Circularly decrements array index i.
+     * Increments i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
      */
-    final int dec(int i) {
-        return ((i == 0) ? items.length : i) - 1;
+    static final int inc(int i, int modulus) {
+        if (++i >= modulus) i = 0;
+        return i;
+    }
+
+    /**
+     * Decrements i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int dec(int i, int modulus) {
+        if (--i < 0) i = modulus - 1;
+        return i;
     }
 
     /**
@@ -144,14 +162,24 @@
     }
 
     /**
+     * Returns element at array index i.
+     * This is a slight abuse of generics, accepted by javac.
+     */
+    @SuppressWarnings("unchecked")
+    static <E> E itemAt(Object[] items, int i) {
+        return (E) items[i];
+    }
+
+    /**
      * Inserts element at current put position, advances, and signals.
      * Call only when holding lock.
      */
-    private void enqueue(E x) {
+    private void enqueue(E e) {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[putIndex] == null;
         final Object[] items = this.items;
-        items[putIndex] = x;
+        items[putIndex] = e;
         if (++putIndex == items.length) putIndex = 0;
         count++;
         notEmpty.signal();
@@ -162,18 +190,19 @@
      * Call only when holding lock.
      */
     private E dequeue() {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[takeIndex] != null;
         final Object[] items = this.items;
         @SuppressWarnings("unchecked")
-        E x = (E) items[takeIndex];
+        E e = (E) items[takeIndex];
         items[takeIndex] = null;
         if (++takeIndex == items.length) takeIndex = 0;
         count--;
         if (itrs != null)
             itrs.elementDequeued();
         notFull.signal();
-        return x;
+        return e;
     }
 
     /**
@@ -182,6 +211,7 @@
      * Call only when holding lock.
      */
     void removeAt(final int removeIndex) {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[removeIndex] != null;
         // assert removeIndex >= 0 && removeIndex < items.length;
@@ -267,6 +297,7 @@
         final ReentrantLock lock = this.lock;
         lock.lock(); // Lock only for visibility, not mutual exclusion
         try {
+            final Object[] items = this.items;
             int i = 0;
             try {
                 for (E e : c)
@@ -481,15 +512,16 @@
         try {
             if (count > 0) {
                 final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    if (o.equals(items[i])) {
-                        removeAt(i);
-                        return true;
-                    }
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        if (o.equals(items[i])) {
+                            removeAt(i);
+                            return true;
+                        }
+                    if (to == end) break;
+                }
             }
             return false;
         } finally {
@@ -512,13 +544,14 @@
         try {
             if (count > 0) {
                 final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    if (o.equals(items[i]))
-                        return true;
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        if (o.equals(items[i]))
+                            return true;
+                    if (to == end) break;
+                }
             }
             return false;
         } finally {
@@ -625,15 +658,9 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            int k = count;
-            if (k > 0) {
-                final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    items[i] = null;
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+            int k;
+            if ((k = count) > 0) {
+                circularClear(items, takeIndex, putIndex);
                 takeIndex = putIndex;
                 count = 0;
                 if (itrs != null)
@@ -647,6 +674,18 @@
     }
 
     /**
+     * Nulls out slots starting at array index i, upto index end.
+     * If i == end, the entire array is cleared!
+     */
+    private static void circularClear(Object[] items, int i, int end) {
+        for (int to = (i < end) ? end : items.length;
+             ; i = 0, to = end) {
+            Arrays.fill(items, i, to, null);
+            if (to == end) break;
+        }
+    }
+
+    /**
      * @throws UnsupportedOperationException {@inheritDoc}
      * @throws ClassCastException            {@inheritDoc}
      * @throws NullPointerException          {@inheritDoc}
@@ -678,8 +717,8 @@
             try {
                 while (i < n) {
                     @SuppressWarnings("unchecked")
-                    E x = (E) items[take];
-                    c.add(x);
+                    E e = (E) items[take];
+                    c.add(e);
                     items[take] = null;
                     if (++take == items.length) take = 0;
                     i++;
@@ -808,7 +847,7 @@
          * there is known to be at least one iterator to collect
          */
         void doSomeSweeping(boolean tryHarder) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert head != null;
             int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
             Node o, p;
@@ -864,7 +903,7 @@
          * Adds a new iterator to the linked list of tracked iterators.
          */
         void register(Itr itr) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             head = new Node(itr, head);
         }
 
@@ -874,7 +913,7 @@
          * Notifies all iterators, and expunges any that are now stale.
          */
         void takeIndexWrapped() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             cycles++;
             for (Node o = null, p = head; p != null;) {
                 final Itr it = p.get();
@@ -931,7 +970,7 @@
          * clears all weak refs, and unlinks the itrs datastructure.
          */
         void queueIsEmpty() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             for (Node p = head; p != null; p = p.next) {
                 Itr it = p.get();
                 if (it != null) {
@@ -947,7 +986,7 @@
          * Called whenever an element has been dequeued (at takeIndex).
          */
         void elementDequeued() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (count == 0)
                 queueIsEmpty();
             else if (takeIndex == 0)
@@ -1008,7 +1047,6 @@
         private static final int DETACHED = -3;
 
         Itr() {
-            // assert lock.getHoldCount() == 0;
             lastRet = NONE;
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
@@ -1041,12 +1079,12 @@
         }
 
         boolean isDetached() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             return prevTakeIndex < 0;
         }
 
         private int incCursor(int index) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (++index == items.length) index = 0;
             if (index == putIndex) index = NONE;
             return index;
@@ -1071,7 +1109,7 @@
          * operation on this iterator.  Call only from iterating thread.
          */
         private void incorporateDequeues() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert itrs != null;
             // assert !isDetached();
             // assert count > 0;
@@ -1114,7 +1152,7 @@
          */
         private void detach() {
             // Switch to detached mode
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert cursor == NONE;
             // assert nextIndex < 0;
             // assert lastRet < 0 || nextItem == null;
@@ -1134,7 +1172,6 @@
          * triggered by queue modifications.
          */
         public boolean hasNext() {
-            // assert lock.getHoldCount() == 0;
             if (nextItem != null)
                 return true;
             noNext();
@@ -1164,9 +1201,8 @@
         }
 
         public E next() {
-            // assert lock.getHoldCount() == 0;
-            final E x = nextItem;
-            if (x == null)
+            final E e = nextItem;
+            if (e == null)
                 throw new NoSuchElementException();
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
@@ -1188,13 +1224,43 @@
             } finally {
                 lock.unlock();
             }
-            return x;
+            return e;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                final E e = nextItem;
+                if (e == null) return;
+                if (!isDetached())
+                    incorporateDequeues();
+                action.accept(e);
+                if (isDetached() || cursor < 0) return;
+                final Object[] items = ArrayBlockingQueue.this.items;
+                for (int i = cursor, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(itemAt(items, i));
+                    if (to == end) break;
+                }
+            } finally {
+                // Calling forEachRemaining is a strong hint that this
+                // iteration is surely over; supporting remove() after
+                // forEachRemaining() is more trouble than it's worth
+                cursor = nextIndex = lastRet = NONE;
+                nextItem = lastItem = null;
+                detach();
+                lock.unlock();
+            }
         }
 
         public void remove() {
-            // assert lock.getHoldCount() == 0;
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
+            // assert lock.getHoldCount() == 1;
             try {
                 if (!isDetached())
                     incorporateDequeues(); // might update lastRet or detach
@@ -1232,7 +1298,7 @@
          * from next(), as promised by returning true from hasNext().
          */
         void shutdown() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             cursor = NONE;
             if (nextIndex >= 0)
                 nextIndex = REMOVED;
@@ -1260,7 +1326,7 @@
          * @return true if this iterator should be unlinked from itrs
          */
         boolean removedAt(int removedIndex) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (isDetached())
                 return true;
 
@@ -1285,7 +1351,7 @@
                 }
                 else if (x > removedDistance) {
                     // assert cursor != prevTakeIndex;
-                    this.cursor = cursor = dec(cursor);
+                    this.cursor = cursor = dec(cursor, len);
                 }
             }
             int lastRet = this.lastRet;
@@ -1294,7 +1360,7 @@
                 if (x == removedDistance)
                     this.lastRet = lastRet = REMOVED;
                 else if (x > removedDistance)
-                    this.lastRet = lastRet = dec(lastRet);
+                    this.lastRet = lastRet = dec(lastRet, len);
             }
             int nextIndex = this.nextIndex;
             if (nextIndex >= 0) {
@@ -1302,7 +1368,7 @@
                 if (x == removedDistance)
                     this.nextIndex = nextIndex = REMOVED;
                 else if (x > removedDistance)
-                    this.nextIndex = nextIndex = dec(nextIndex);
+                    this.nextIndex = nextIndex = dec(nextIndex, len);
             }
             if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
                 this.prevTakeIndex = DETACHED;
@@ -1317,7 +1383,7 @@
          * @return true if this iterator should be unlinked from itrs
          */
         boolean takeIndexWrapped() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (isDetached())
                 return true;
             if (itrs.cycles - prevCycles > 1) {
@@ -1366,4 +1432,170 @@
                     Spliterator.CONCURRENT));
     }
 
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(itemAt(items, i));
+                    if (to == end) break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (itrs == null) { // check for active iterators
+                if (count > 0) {
+                    final Object[] items = this.items;
+                    // Optimize for initial run of survivors
+                    for (int i = takeIndex, end = putIndex,
+                             to = (i < end) ? end : items.length;
+                         ; i = 0, to = end) {
+                        for (; i < to; i++)
+                            if (filter.test(itemAt(items, i)))
+                                return bulkRemoveModified(filter, i);
+                        if (to == end) break;
+                    }
+                }
+                return false;
+            }
+        } finally {
+            lock.unlock();
+        }
+        // Active iterators are too hairy!
+        // Punting (for now) to the slow n^2 algorithm ...
+        return super.removeIf(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /**
+     * Returns circular distance from i to j, disambiguating i == j to
+     * items.length; never returns 0.
+     */
+    private int distanceNonEmpty(int i, int j) {
+        if ((j -= i) <= 0) j += items.length;
+        return j;
+    }
+
+    /**
+     * Helper for bulkRemove, in case of at least one deletion.
+     * Tolerate predicates that reentrantly access the collection for
+     * read (but not write), so traverse once to find elements to
+     * delete, a second pass to physically expunge.
+     *
+     * @param beg valid index of first element to be deleted
+     */
+    private boolean bulkRemoveModified(
+        Predicate<? super E> filter, final int beg) {
+        final Object[] es = items;
+        final int capacity = items.length;
+        final int end = putIndex;
+        final long[] deathRow = nBits(distanceNonEmpty(beg, putIndex));
+        deathRow[0] = 1L;   // set bit 0
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; i = 0, to = end, k -= capacity) {
+            for (; i < to; i++)
+                if (filter.test(itemAt(es, i)))
+                    setBit(deathRow, i - k);
+            if (to == end) break;
+        }
+        // a two-finger traversal, with hare i reading, tortoise w writing
+        int w = beg;
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; w = 0) { // w rejoins i on second leg
+            // In this loop, i and w are on the same leg, with i > w
+            for (; i < to; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (to == end) break;
+            // In this loop, w is on the first leg, i on the second
+            for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (i >= to) {
+                if (w == capacity) w = 0; // "corner" case
+                break;
+            }
+        }
+        count -= distanceNonEmpty(w, end);
+        circularClear(es, putIndex = w, end);
+        return true;
+    }
+
+    /** debugging */
+    void checkInvariants() {
+        // meta-assertions
+        // assert lock.isHeldByCurrentThread();
+        try {
+            // Unlike ArrayDeque, we have a count field but no spare slot.
+            // We prefer ArrayDeque's strategy (and the names of its fields!),
+            // but our field layout is baked into the serial form, and so is
+            // too annoying to change.
+            //
+            // putIndex == takeIndex must be disambiguated by checking count.
+            int capacity = items.length;
+            // assert capacity > 0;
+            // assert takeIndex >= 0 && takeIndex < capacity;
+            // assert putIndex >= 0 && putIndex < capacity;
+            // assert count <= capacity;
+            // assert takeIndex == putIndex || items[takeIndex] != null;
+            // assert count == capacity || items[putIndex] == null;
+            // assert takeIndex == putIndex || items[dec(putIndex, capacity)] != null;
+        } catch (Throwable t) {
+            System.err.printf("takeIndex=%d putIndex=%d count=%d capacity=%d%n",
+                              takeIndex, putIndex, count, items.length);
+            System.err.printf("items=%s%n",
+                              Arrays.toString(items));
+            throw t;
+        }
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java	Wed Jul 05 22:32:06 2017 +0200
@@ -856,13 +856,9 @@
      * CompletableFuture, this method may return this stage itself.
      * Otherwise, invocation of this method may be equivalent in
      * effect to {@code thenApply(x -> x)}, but returning an instance
-     * of type {@code CompletableFuture}. A CompletionStage
-     * implementation that does not choose to interoperate with others
-     * may throw {@code UnsupportedOperationException}.
+     * of type {@code CompletableFuture}.
      *
      * @return the CompletableFuture
-     * @throws UnsupportedOperationException if this implementation
-     * does not interoperate with CompletableFuture
      */
     public CompletableFuture<T> toCompletableFuture();
 
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1650,7 +1650,24 @@
      * Removes all of the mappings from this map.
      */
     public void clear() {
-        initialize();
+        for (;;) {
+            Node<K,V> b, n;
+            HeadIndex<K,V> h = head, d = (HeadIndex<K,V>)h.down;
+            if (d != null)
+                casHead(h, d);            // remove levels
+            else if ((b = h.node) != null && (n = b.next) != null) {
+                Node<K,V> f = n.next;     // remove values
+                if (n == b.next) {
+                    Object v = n.value;
+                    if (v == null)
+                        n.helpDelete(b, f);
+                    else if (n.casValue(v, null) && n.appendMarker(f))
+                        b.casNext(n, f);
+                }
+            }
+            else
+                break;
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Wed Jul 05 22:32:06 2017 +0200
@@ -380,7 +380,7 @@
     // Positional Access Operations
 
     @SuppressWarnings("unchecked")
-    private E get(Object[] a, int index) {
+    static <E> E elementAt(Object[] a, int index) {
         return (E) a[index];
     }
 
@@ -394,7 +394,7 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public E get(int index) {
-        return get(getArray(), index);
+        return elementAt(getArray(), index);
     }
 
     /**
@@ -406,7 +406,7 @@
     public E set(int index, E element) {
         synchronized (lock) {
             Object[] elements = getArray();
-            E oldValue = get(elements, index);
+            E oldValue = elementAt(elements, index);
 
             if (oldValue != element) {
                 int len = elements.length;
@@ -477,7 +477,7 @@
         synchronized (lock) {
             Object[] elements = getArray();
             int len = elements.length;
-            E oldValue = get(elements, index);
+            E oldValue = elementAt(elements, index);
             int numMoved = len - index - 1;
             if (numMoved == 0)
                 setArray(Arrays.copyOf(elements, len - 1));
@@ -644,34 +644,16 @@
      * @return {@code true} if this list changed as a result of the call
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this list contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
     public boolean removeAll(Collection<?> c) {
-        if (c == null) throw new NullPointerException();
-        synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            if (len != 0) {
-                // temp array holds those elements we know we want to keep
-                int newlen = 0;
-                Object[] temp = new Object[len];
-                for (int i = 0; i < len; ++i) {
-                    Object element = elements[i];
-                    if (!c.contains(element))
-                        temp[newlen++] = element;
-                }
-                if (newlen != len) {
-                    setArray(Arrays.copyOf(temp, newlen));
-                    return true;
-                }
-            }
-            return false;
-        }
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
     }
 
     /**
@@ -683,34 +665,16 @@
      * @return {@code true} if this list changed as a result of the call
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this list contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
     public boolean retainAll(Collection<?> c) {
-        if (c == null) throw new NullPointerException();
-        synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            if (len != 0) {
-                // temp array holds those elements we know we want to keep
-                int newlen = 0;
-                Object[] temp = new Object[len];
-                for (int i = 0; i < len; ++i) {
-                    Object element = elements[i];
-                    if (c.contains(element))
-                        temp[newlen++] = element;
-                }
-                if (newlen != len) {
-                    setArray(Arrays.copyOf(temp, newlen));
-                    return true;
-                }
-            }
-            return false;
-        }
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
     }
 
     /**
@@ -839,55 +803,90 @@
 
     public boolean removeIf(Predicate<? super E> filter) {
         if (filter == null) throw new NullPointerException();
+        return bulkRemove(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    private boolean bulkRemove(Predicate<? super E> filter) {
         synchronized (lock) {
-            final Object[] elements = getArray();
-            final int len = elements.length;
-            int i;
-            for (i = 0; i < len; i++) {
-                @SuppressWarnings("unchecked") E e = (E) elements[i];
-                if (filter.test(e)) {
-                    int newlen = i;
-                    final Object[] newElements = new Object[len - 1];
-                    System.arraycopy(elements, 0, newElements, 0, newlen);
-                    for (i++; i < len; i++) {
-                        @SuppressWarnings("unchecked") E x = (E) elements[i];
-                        if (!filter.test(x))
-                            newElements[newlen++] = x;
-                    }
-                    setArray((newlen == len - 1)
-                             ? newElements // one match => one copy
-                             : Arrays.copyOf(newElements, newlen));
-                    return true;
+            return bulkRemove(filter, 0, getArray().length);
+        }
+    }
+
+    boolean bulkRemove(Predicate<? super E> filter, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray();
+        // Optimize for initial run of survivors
+        for (; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            int deleted = 1;
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i))) {
+                    setBit(deathRow, i - beg);
+                    deleted++;
                 }
-            }
-            return false;       // zero matches => zero copies
+            // Did filter reentrantly modify the list?
+            if (es != getArray())
+                throw new ConcurrentModificationException();
+            final Object[] newElts = Arrays.copyOf(es, es.length - deleted);
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    newElts[w++] = es[i];
+            System.arraycopy(es, i, newElts, w, es.length - i);
+            setArray(newElts);
+            return true;
+        } else {
+            if (es != getArray())
+                throw new ConcurrentModificationException();
+            return false;
         }
     }
 
     public void replaceAll(UnaryOperator<E> operator) {
         if (operator == null) throw new NullPointerException();
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            Object[] newElements = Arrays.copyOf(elements, len);
-            for (int i = 0; i < len; ++i) {
-                @SuppressWarnings("unchecked") E e = (E) elements[i];
-                newElements[i] = operator.apply(e);
-            }
-            setArray(newElements);
+            replaceAll(operator, 0, getArray().length);
         }
     }
 
+    void replaceAll(UnaryOperator<E> operator, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray().clone();
+        for (; i < end; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        setArray(es);
+    }
+
     public void sort(Comparator<? super E> c) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            Object[] newElements = Arrays.copyOf(elements, elements.length);
-            @SuppressWarnings("unchecked") E[] es = (E[])newElements;
-            Arrays.sort(es, c);
-            setArray(newElements);
+            sort(c, 0, getArray().length);
         }
     }
 
+    @SuppressWarnings("unchecked")
+    void sort(Comparator<? super E> c, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray().clone();
+        Arrays.sort(es, i, end, (Comparator<Object>)c);
+        setArray(es);
+    }
+
     /**
      * Saves this list to a stream (that is, serializes it).
      *
@@ -1167,18 +1166,6 @@
 
     /**
      * Sublist for CopyOnWriteArrayList.
-     * This class extends AbstractList merely for convenience, to
-     * avoid having to define addAll, etc. This doesn't hurt, but
-     * is wasteful.  This class does not need or use modCount
-     * mechanics in AbstractList, but does need to check for
-     * concurrent modification using similar mechanics.  On each
-     * operation, the array that we expect the backing list to use
-     * is checked and updated.  Since we do this for all of the
-     * base operations invoked by those defined in AbstractList,
-     * all is well.  While inefficient, this is not worth
-     * improving.  The kinds of list operations inherited from
-     * AbstractList are already so slow on COW sublists that
-     * adding a bit more space/time doesn't seem even noticeable.
      */
     private static class COWSubList<E>
         extends AbstractList<E>
@@ -1206,6 +1193,14 @@
                 throw new ConcurrentModificationException();
         }
 
+        private Object[] getArrayChecked() {
+            // assert Thread.holdsLock(l.lock);
+            Object[] a = l.getArray();
+            if (a != expectedArray)
+                throw new ConcurrentModificationException();
+            return a;
+        }
+
         // only call this holding l's lock
         private void rangeCheck(int index) {
             // assert Thread.holdsLock(l.lock);
@@ -1217,7 +1212,7 @@
             synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E x = l.set(index+offset, element);
+                E x = l.set(offset + index, element);
                 expectedArray = l.getArray();
                 return x;
             }
@@ -1227,7 +1222,7 @@
             synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                return l.get(index+offset);
+                return l.get(offset + index);
             }
         }
 
@@ -1238,22 +1233,41 @@
             }
         }
 
+        public boolean add(E element) {
+            synchronized (l.lock) {
+                checkForComodification();
+                l.add(offset + size, element);
+                expectedArray = l.getArray();
+                size++;
+            }
+            return true;
+        }
+
         public void add(int index, E element) {
             synchronized (l.lock) {
                 checkForComodification();
                 if (index < 0 || index > size)
                     throw new IndexOutOfBoundsException
                         (outOfBounds(index, size));
-                l.add(index+offset, element);
+                l.add(offset + index, element);
                 expectedArray = l.getArray();
                 size++;
             }
         }
 
+        public boolean addAll(Collection<? extends E> c) {
+            synchronized (l.lock) {
+                final Object[] oldArray = getArrayChecked();
+                boolean modified = l.addAll(offset + size, c);
+                size += (expectedArray = l.getArray()).length - oldArray.length;
+                return modified;
+            }
+        }
+
         public void clear() {
             synchronized (l.lock) {
                 checkForComodification();
-                l.removeRange(offset, offset+size);
+                l.removeRange(offset, offset + size);
                 expectedArray = l.getArray();
                 size = 0;
             }
@@ -1263,7 +1277,7 @@
             synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E result = l.remove(index+offset);
+                E result = l.remove(offset + index);
                 expectedArray = l.getArray();
                 size--;
                 return result;
@@ -1271,11 +1285,14 @@
         }
 
         public boolean remove(Object o) {
-            int index = indexOf(o);
-            if (index == -1)
-                return false;
-            remove(index);
-            return true;
+            synchronized (l.lock) {
+                checkForComodification();
+                int index = indexOf(o);
+                if (index == -1)
+                    return false;
+                remove(index);
+                return true;
+            }
         }
 
         public Iterator<E> iterator() {
@@ -1307,174 +1324,63 @@
 
         public void forEach(Consumer<? super E> action) {
             if (action == null) throw new NullPointerException();
-            int lo = offset;
-            int hi = offset + size;
-            Object[] a = expectedArray;
-            if (l.getArray() != a)
-                throw new ConcurrentModificationException();
-            if (lo < 0 || hi > a.length)
-                throw new IndexOutOfBoundsException();
-            for (int i = lo; i < hi; ++i) {
-                @SuppressWarnings("unchecked") E e = (E) a[i];
-                action.accept(e);
+            int i, end; final Object[] es;
+            synchronized (l.lock) {
+                es = getArrayChecked();
+                i = offset;
+                end = i + size;
             }
+            for (; i < end; i++)
+                action.accept(elementAt(es, i));
         }
 
         public void replaceAll(UnaryOperator<E> operator) {
             if (operator == null) throw new NullPointerException();
             synchronized (l.lock) {
-                int lo = offset;
-                int hi = offset + size;
-                Object[] elements = expectedArray;
-                if (l.getArray() != elements)
-                    throw new ConcurrentModificationException();
-                int len = elements.length;
-                if (lo < 0 || hi > len)
-                    throw new IndexOutOfBoundsException();
-                Object[] newElements = Arrays.copyOf(elements, len);
-                for (int i = lo; i < hi; ++i) {
-                    @SuppressWarnings("unchecked") E e = (E) elements[i];
-                    newElements[i] = operator.apply(e);
-                }
-                l.setArray(expectedArray = newElements);
+                checkForComodification();
+                l.replaceAll(operator, offset, offset + size);
+                expectedArray = l.getArray();
             }
         }
 
         public void sort(Comparator<? super E> c) {
             synchronized (l.lock) {
-                int lo = offset;
-                int hi = offset + size;
-                Object[] elements = expectedArray;
-                if (l.getArray() != elements)
-                    throw new ConcurrentModificationException();
-                int len = elements.length;
-                if (lo < 0 || hi > len)
-                    throw new IndexOutOfBoundsException();
-                Object[] newElements = Arrays.copyOf(elements, len);
-                @SuppressWarnings("unchecked") E[] es = (E[])newElements;
-                Arrays.sort(es, lo, hi, c);
-                l.setArray(expectedArray = newElements);
+                checkForComodification();
+                l.sort(c, offset, offset + size);
+                expectedArray = l.getArray();
             }
         }
 
         public boolean removeAll(Collection<?> c) {
-            if (c == null) throw new NullPointerException();
-            boolean removed = false;
-            synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        Object element = elements[i];
-                        if (!c.contains(element))
-                            temp[newSize++] = element;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
-            }
-            return removed;
+            Objects.requireNonNull(c);
+            return bulkRemove(e -> c.contains(e));
         }
 
         public boolean retainAll(Collection<?> c) {
-            if (c == null) throw new NullPointerException();
-            boolean removed = false;
-            synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        Object element = elements[i];
-                        if (c.contains(element))
-                            temp[newSize++] = element;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
-            }
-            return removed;
+            Objects.requireNonNull(c);
+            return bulkRemove(e -> !c.contains(e));
         }
 
         public boolean removeIf(Predicate<? super E> filter) {
-            if (filter == null) throw new NullPointerException();
-            boolean removed = false;
+            Objects.requireNonNull(filter);
+            return bulkRemove(filter);
+        }
+
+        private boolean bulkRemove(Predicate<? super E> filter) {
             synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        @SuppressWarnings("unchecked") E e = (E) elements[i];
-                        if (!filter.test(e))
-                            temp[newSize++] = e;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
+                final Object[] oldArray = getArrayChecked();
+                boolean modified = l.bulkRemove(filter, offset, offset + size);
+                size += (expectedArray = l.getArray()).length - oldArray.length;
+                return modified;
             }
-            return removed;
         }
 
         public Spliterator<E> spliterator() {
-            int lo = offset;
-            int hi = offset + size;
-            Object[] a = expectedArray;
-            if (l.getArray() != a)
-                throw new ConcurrentModificationException();
-            if (lo < 0 || hi > a.length)
-                throw new IndexOutOfBoundsException();
-            return Spliterators.spliterator
-                (a, lo, hi, Spliterator.IMMUTABLE | Spliterator.ORDERED);
+            synchronized (l.lock) {
+                return Spliterators.spliterator(
+                        getArrayChecked(), offset, offset + size,
+                        Spliterator.IMMUTABLE | Spliterator.ORDERED);
+            }
         }
 
     }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java	Wed Jul 05 22:32:06 2017 +0200
@@ -82,8 +82,7 @@
  *   public Solver(float[][] matrix) {
  *     data = matrix;
  *     N = matrix.length;
- *     Runnable barrierAction =
- *       new Runnable() { public void run() { mergeRows(...); }};
+ *     Runnable barrierAction = () -> mergeRows(...);
  *     barrier = new CyclicBarrier(N, barrierAction);
  *
  *     List<Thread> threads = new ArrayList<>(N);
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Executor.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Executor.java	Wed Jul 05 22:32:06 2017 +0200
@@ -87,14 +87,12 @@
  *     this.executor = executor;
  *   }
  *
- *   public synchronized void execute(final Runnable r) {
- *     tasks.add(new Runnable() {
- *       public void run() {
- *         try {
- *           r.run();
- *         } finally {
- *           scheduleNext();
- *         }
+ *   public synchronized void execute(Runnable r) {
+ *     tasks.add(() -> {
+ *       try {
+ *         r.run();
+ *       } finally {
+ *         scheduleNext();
  *       }
  *     });
  *     if (active == null) {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java	Wed Jul 05 22:32:06 2017 +0200
@@ -80,7 +80,7 @@
  *   List<Future<Result>> futures = new ArrayList<>(n);
  *   Result result = null;
  *   try {
- *     solvers.forEach((solver) -> futures.add(cs.submit(solver)));
+ *     solvers.forEach(solver -> futures.add(cs.submit(solver)));
  *     for (int i = n; i > 0; i--) {
  *       try {
  *         Result r = cs.take().get();
@@ -91,7 +91,7 @@
  *       } catch (ExecutionException ignore) {}
  *     }
  *   } finally {
- *     futures.forEach((future) -> future.cancel(true));
+ *     futures.forEach(future -> future.cancel(true));
  *   }
  *
  *   if (result != null)
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Executors.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Executors.java	Wed Jul 05 22:32:06 2017 +0200
@@ -650,7 +650,7 @@
         public Thread newThread(final Runnable r) {
             return super.newThread(new Runnable() {
                 public void run() {
-                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    AccessController.doPrivileged(new PrivilegedAction<>() {
                         public Void run() {
                             Thread.currentThread().setContextClassLoader(ccl);
                             r.run();
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,8 +38,10 @@
 import java.lang.Thread.UncaughtExceptionHandler;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
+import java.security.AccessController;
 import java.security.AccessControlContext;
 import java.security.Permissions;
+import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -64,7 +66,8 @@
  * tasks are submitted to the pool from external clients.  Especially
  * when setting <em>asyncMode</em> to true in constructors, {@code
  * ForkJoinPool}s may also be appropriate for use with event-style
- * tasks that are never joined.
+ * tasks that are never joined. All worker threads are initialized
+ * with {@link Thread#isDaemon} set {@code true}.
  *
  * <p>A static {@link #commonPool()} is available and appropriate for
  * most applications. The common pool is used by any ForkJoinTask that
@@ -3224,10 +3227,9 @@
             new DefaultForkJoinWorkerThreadFactory();
         modifyThreadPermission = new RuntimePermission("modifyThread");
 
-        common = java.security.AccessController.doPrivileged
-            (new java.security.PrivilegedAction<ForkJoinPool>() {
-                    public ForkJoinPool run() {
-                        return new ForkJoinPool((byte)0); }});
+        common = AccessController.doPrivileged(new PrivilegedAction<>() {
+            public ForkJoinPool run() {
+                return new ForkJoinPool((byte)0); }});
 
         COMMON_PARALLELISM = Math.max(common.mode & SMASK, 1);
     }
@@ -3256,12 +3258,11 @@
         }
 
         public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
-            return java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<ForkJoinWorkerThread>() {
-                    public ForkJoinWorkerThread run() {
-                        return new ForkJoinWorkerThread.
-                            InnocuousForkJoinWorkerThread(pool);
-                    }}, INNOCUOUS_ACC);
+            return AccessController.doPrivileged(new PrivilegedAction<>() {
+                public ForkJoinWorkerThread run() {
+                    return new ForkJoinWorkerThread.
+                        InnocuousForkJoinWorkerThread(pool);
+                }}, INNOCUOUS_ACC);
         }
     }
 
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Wed Jul 05 22:32:06 2017 +0200
@@ -419,7 +419,7 @@
 
     /** Reference queue of stale exceptionally completed tasks. */
     private static final ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue
-        = new ReferenceQueue<ForkJoinTask<?>>();
+        = new ReferenceQueue<>();
 
     /**
      * Key-value nodes for exception table.  The chained hash table
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Future.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Future.java	Wed Jul 05 22:32:06 2017 +0200
@@ -50,8 +50,7 @@
  * declare types of the form {@code Future<?>} and
  * return {@code null} as a result of the underlying task.
  *
- * <p>
- * <b>Sample Usage</b> (Note that the following classes are all
+ * <p><b>Sample Usage</b> (Note that the following classes are all
  * made-up.)
  *
  * <pre> {@code
@@ -59,13 +58,9 @@
  * class App {
  *   ExecutorService executor = ...
  *   ArchiveSearcher searcher = ...
- *   void showSearch(final String target)
- *       throws InterruptedException {
- *     Future<String> future
- *       = executor.submit(new Callable<String>() {
- *         public String call() {
- *             return searcher.search(target);
- *         }});
+ *   void showSearch(String target) throws InterruptedException {
+ *     Callable<String> task = () -> searcher.search(target);
+ *     Future<String> future = executor.submit(task);
  *     displayOtherThings(); // do other things while searching
  *     try {
  *       displayText(future.get()); // use future
@@ -77,11 +72,7 @@
  * implements {@code Runnable}, and so may be executed by an {@code Executor}.
  * For example, the above construction with {@code submit} could be replaced by:
  * <pre> {@code
- * FutureTask<String> future =
- *   new FutureTask<>(new Callable<String>() {
- *     public String call() {
- *       return searcher.search(target);
- *   }});
+ * FutureTask<String> future = new FutureTask<>(task);
  * executor.execute(future);}</pre>
  *
  * <p>Memory consistency effects: Actions taken by the asynchronous computation
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1127,40 +1127,35 @@
     }
 
     /** A customized variant of Spliterators.IteratorSpliterator */
-    static final class LBDSpliterator<E> implements Spliterator<E> {
+    private final class LBDSpliterator implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
-        final LinkedBlockingDeque<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
         long est;           // size estimate
-        LBDSpliterator(LinkedBlockingDeque<E> queue) {
-            this.queue = queue;
-            this.est = queue.size();
-        }
+
+        LBDSpliterator() { est = size(); }
 
         public long estimateSize() { return est; }
 
         public Spliterator<E> trySplit() {
             Node<E> h;
-            final LinkedBlockingDeque<E> q = this.queue;
             int b = batch;
             int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
             if (!exhausted &&
-                ((h = current) != null || (h = q.first) != null) &&
-                h.next != null) {
+                (((h = current) != null && h != h.next)
+                 || (h = first) != null)
+                && h.next != null) {
                 Object[] a = new Object[n];
-                final ReentrantLock lock = q.lock;
+                final ReentrantLock lock = LinkedBlockingDeque.this.lock;
                 int i = 0;
                 Node<E> p = current;
                 lock.lock();
                 try {
-                    if (p != null || (p = q.first) != null) {
-                        do {
-                            if ((a[i] = p.item) != null)
-                                ++i;
-                        } while ((p = p.next) != null && i < n);
-                    }
+                    if (((p != null && p != p.next) || (p = first) != null)
+                        && p.item != null)
+                        for (; p != null && i < n; p = p.next)
+                            a[i++] = p.item;
                 } finally {
                     lock.unlock();
                 }
@@ -1183,64 +1178,55 @@
 
         public void forEachRemaining(Consumer<? super E> action) {
             if (action == null) throw new NullPointerException();
-            final LinkedBlockingDeque<E> q = this.queue;
-            final ReentrantLock lock = q.lock;
-            if (!exhausted) {
-                exhausted = true;
-                Node<E> p = current;
-                do {
-                    E e = null;
-                    lock.lock();
-                    try {
-                        if (p == null)
-                            p = q.first;
-                        while (p != null) {
-                            e = p.item;
-                            p = p.next;
-                            if (e != null)
-                                break;
-                        }
-                    } finally {
-                        lock.unlock();
+            if (exhausted)
+                return;
+            exhausted = true;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            Node<E> p = current;
+            current = null;
+            do {
+                E e = null;
+                lock.lock();
+                try {
+                    if ((p != null && p != p.next) || (p = first) != null) {
+                        e = p.item;
+                        p = p.next;
                     }
-                    if (e != null)
-                        action.accept(e);
-                } while (p != null);
-            }
+                } finally {
+                    lock.unlock();
+                }
+                if (e != null)
+                    action.accept(e);
+            } while (p != null);
         }
 
         public boolean tryAdvance(Consumer<? super E> action) {
             if (action == null) throw new NullPointerException();
-            final LinkedBlockingDeque<E> q = this.queue;
-            final ReentrantLock lock = q.lock;
-            if (!exhausted) {
-                E e = null;
-                lock.lock();
-                try {
-                    if (current == null)
-                        current = q.first;
-                    while (current != null) {
-                        e = current.item;
-                        current = current.next;
-                        if (e != null)
-                            break;
-                    }
-                } finally {
-                    lock.unlock();
+            if (exhausted)
+                return false;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            Node<E> p = current;
+            E e = null;
+            lock.lock();
+            try {
+                if ((p != null && p != p.next) || (p = first) != null) {
+                    e = p.item;
+                    p = p.next;
                 }
-                if (current == null)
-                    exhausted = true;
-                if (e != null) {
-                    action.accept(e);
-                    return true;
-                }
+            } finally {
+                lock.unlock();
             }
-            return false;
+            exhausted = ((current = p) == null);
+            if (e == null)
+                return false;
+            action.accept(e);
+            return true;
         }
 
         public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.NONNULL |
-                Spliterator.CONCURRENT;
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
         }
     }
 
@@ -1261,7 +1247,7 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new LBDSpliterator<E>(this);
+        return new LBDSpliterator();
     }
 
     /**
@@ -1312,4 +1298,14 @@
         }
     }
 
+    void checkInvariants() {
+        // assert lock.isHeldByCurrentThread();
+        // Nodes may get self-linked or lose their item, but only
+        // after being unlinked and becoming unreachable from first.
+        for (Node<E> p = first; p != null; p = p.next) {
+            // assert p.next != p;
+            // assert p.item != null;
+        }
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java	Wed Jul 05 22:32:06 2017 +0200
@@ -95,8 +95,8 @@
      * *** Overview of Dual Queues with Slack ***
      *
      * Dual Queues, introduced by Scherer and Scott
-     * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are
-     * (linked) queues in which nodes may represent either data or
+     * (http://www.cs.rochester.edu/~scott/papers/2004_DISC_dual_DS.pdf)
+     * are (linked) queues in which nodes may represent either data or
      * requests.  When a thread tries to enqueue a data node, but
      * encounters a request node, it instead "matches" and removes it;
      * and vice versa for enqueuing requests. Blocking Dual Queues
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java	Wed Jul 05 22:32:06 2017 +0200
@@ -154,49 +154,46 @@
  * <p>A {@code Phaser} may be used instead of a {@code CountDownLatch}
  * to control a one-shot action serving a variable number of parties.
  * The typical idiom is for the method setting this up to first
- * register, then start the actions, then deregister, as in:
+ * register, then start all the actions, then deregister, as in:
  *
  * <pre> {@code
  * void runTasks(List<Runnable> tasks) {
- *   final Phaser phaser = new Phaser(1); // "1" to register self
+ *   Phaser startingGate = new Phaser(1); // "1" to register self
  *   // create and start threads
- *   for (final Runnable task : tasks) {
- *     phaser.register();
- *     new Thread() {
- *       public void run() {
- *         phaser.arriveAndAwaitAdvance(); // await all creation
- *         task.run();
- *       }
- *     }.start();
+ *   for (Runnable task : tasks) {
+ *     startingGate.register();
+ *     new Thread(() -> {
+ *       startingGate.arriveAndAwaitAdvance();
+ *       task.run();
+ *     }).start();
  *   }
  *
- *   // allow threads to start and deregister self
- *   phaser.arriveAndDeregister();
+ *   // deregister self to allow threads to proceed
+ *   startingGate.arriveAndDeregister();
  * }}</pre>
  *
  * <p>One way to cause a set of threads to repeatedly perform actions
  * for a given number of iterations is to override {@code onAdvance}:
  *
  * <pre> {@code
- * void startTasks(List<Runnable> tasks, final int iterations) {
- *   final Phaser phaser = new Phaser() {
+ * void startTasks(List<Runnable> tasks, int iterations) {
+ *   Phaser phaser = new Phaser() {
  *     protected boolean onAdvance(int phase, int registeredParties) {
  *       return phase >= iterations || registeredParties == 0;
  *     }
  *   };
  *   phaser.register();
- *   for (final Runnable task : tasks) {
+ *   for (Runnable task : tasks) {
  *     phaser.register();
- *     new Thread() {
- *       public void run() {
- *         do {
- *           task.run();
- *           phaser.arriveAndAwaitAdvance();
- *         } while (!phaser.isTerminated());
- *       }
- *     }.start();
+ *     new Thread(() -> {
+ *       do {
+ *         task.run();
+ *         phaser.arriveAndAwaitAdvance();
+ *       } while (!phaser.isTerminated());
+ *     }).start();
  *   }
- *   phaser.arriveAndDeregister(); // deregister self, don't wait
+ *   // allow threads to proceed; don't wait for them
+ *   phaser.arriveAndDeregister();
  * }}</pre>
  *
  * If the main task must later await termination, it
--- a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Wed Jul 05 22:32:06 2017 +0200
@@ -933,8 +933,9 @@
         }
     }
 
-    // Similar to Collections.ArraySnapshotSpliterator but avoids
-    // commitment to toArray until needed
+    /**
+     * Immutable snapshot spliterator that binds to elements "late".
+     */
     static final class PBQSpliterator<E> implements Spliterator<E> {
         final PriorityBlockingQueue<E> queue;
         Object[] array;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledExecutorService.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledExecutorService.java	Wed Jul 05 22:32:06 2017 +0200
@@ -77,14 +77,11 @@
  *     Executors.newScheduledThreadPool(1);
  *
  *   public void beepForAnHour() {
- *     final Runnable beeper = new Runnable() {
- *       public void run() { System.out.println("beep"); }
- *     };
- *     final ScheduledFuture<?> beeperHandle =
+ *     Runnable beeper = () -> System.out.println("beep");
+ *     ScheduledFuture<?> beeperHandle =
  *       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
- *     scheduler.schedule(new Runnable() {
- *       public void run() { beeperHandle.cancel(true); }
- *     }, 60 * 60, SECONDS);
+ *     Runnable canceller = () -> beeperHandle.cancel(true);
+ *     scheduler.schedule(canceller, 1, HOURS);
  *   }
  * }}</pre>
  *
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Semaphore.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Semaphore.java	Wed Jul 05 22:32:06 2017 +0200
@@ -631,9 +631,12 @@
     }
 
     /**
-     * Acquires and returns all permits that are immediately available.
+     * Acquires and returns all permits that are immediately
+     * available, or if negative permits are available, releases them.
+     * Upon return, zero permits are available.
      *
-     * @return the number of permits acquired
+     * @return the number of permits acquired or, if negative, the
+     * number released
      */
     public int drainPermits() {
         return sync.drainPermits();
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Wed Jul 05 22:32:06 2017 +0200
@@ -197,9 +197,17 @@
         return r;
     }
 
-    // We must define this, but never use it.
+    /**
+     * Generates a pseudorandom number with the indicated number of
+     * low-order bits.  Because this class has no subclasses, this
+     * method cannot be invoked or overridden.
+     *
+     * @param  bits random bits
+     * @return the next pseudorandom value from this random number
+     *         generator's sequence
+     */
     protected int next(int bits) {
-        return (int)(mix64(nextSeed()) >>> (64 - bits));
+        return nextInt() >>> (32 - bits);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Wed Jul 05 22:32:06 2017 +0200
@@ -60,6 +60,10 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
@@ -105,8 +109,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean compareAndSet(T obj, int expect, int update);
 
@@ -125,8 +127,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean weakCompareAndSet(T obj, int expect, int update);
 
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Wed Jul 05 22:32:06 2017 +0200
@@ -60,6 +60,10 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
@@ -108,8 +112,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean compareAndSet(T obj, long expect, long update);
 
@@ -128,8 +130,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean weakCompareAndSet(T obj, long expect, long update);
 
@@ -510,8 +510,8 @@
 
         LockedUpdater(final Class<T> tclass, final String fieldName,
                       final Class<?> caller) {
-            Field field = null;
-            int modifiers = 0;
+            final Field field;
+            final int modifiers;
             try {
                 field = AccessController.doPrivileged(
                     new PrivilegedExceptionAction<Field>() {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Wed Jul 05 22:32:06 2017 +0200
@@ -77,6 +77,10 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/package-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/package-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -60,21 +60,9 @@
  *   }
  * }}</pre>
  *
- * <p>It is straightforward to define new utility functions that, like
- * {@code getAndIncrement}, apply a function to a value atomically.
- * For example, given some transformation
- * <pre> {@code long transform(long input)}</pre>
- *
- * write your utility method as follows:
- * <pre> {@code
- * long getAndTransform(AtomicLong var) {
- *   long prev, next;
- *   do {
- *     prev = var.get();
- *     next = transform(prev);
- *   } while (!var.compareAndSet(prev, next));
- *   return prev; // return next; for transformAndGet
- * }}</pre>
+ * <p>Arbitrary transformations of the contained value are provided both
+ * by low-level read-modify-write operations such as {@code compareAndSet}
+ * and by higher-level methods such as {@code getAndUpdate}.
  *
  * <p>These classes are not general purpose replacements for {@code
  * java.lang.Integer} and related classes.  They do <em>not</em>
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Wed Jul 05 22:32:06 2017 +0200
@@ -572,7 +572,7 @@
      * before acquiring the lock
      */
     @ReservedStackAccess
-        public long readLockInterruptibly() throws InterruptedException {
+    public long readLockInterruptibly() throws InterruptedException {
         long s, next;
         if (!Thread.interrupted()
             // bypass acquireRead on common uncontended case
--- a/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -200,7 +200,7 @@
  * concurrent collection is thread-safe, but not governed by a
  * single exclusion lock.  In the particular case of
  * ConcurrentHashMap, it safely permits any number of
- * concurrent reads as well as a tunable number of concurrent
+ * concurrent reads as well as a large number of concurrent
  * writes.  "Synchronized" classes can be useful when you need
  * to prevent all access to a collection via a single lock, at
  * the expense of poorer scalability.  In other cases in which
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Wed Jul 05 22:32:06 2017 +0200
@@ -48,8 +48,8 @@
  * processing multi-release jar files.  The {@code Manifest} can be used
  * to specify meta-information about the jar file and its entries.
  *
- * <p>A multi-release jar file is a jar file that contains
- * a manifest with a main attribute named "Multi-Release",
+ * <p><a name="multirelease">A multi-release jar file</a> is a jar file that
+ * contains a manifest with a main attribute named "Multi-Release",
  * a set of "base" entries, some of which are public classes with public
  * or protected methods that comprise the public interface of the jar file,
  * and a set of "versioned" entries contained in subdirectories of the
--- a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,37 +25,47 @@
 
 package java.util.spi;
 
+import jdk.internal.misc.JavaUtilResourceBundleAccess;
+import jdk.internal.misc.SharedSecrets;
+
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.UncheckedIOException;
 import java.lang.reflect.Module;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Locale;
+import java.util.PropertyResourceBundle;
 import java.util.ResourceBundle;
-import sun.util.locale.provider.ResourceBundleProviderSupport;
 import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
 
-
 /**
- * {@code AbstractResourceBundleProvider} is an abstract class for helping
- * implement the {@link ResourceBundleProvider} interface.
+ * {@code AbstractResourceBundleProvider} is an abstract class that provides
+ * the basic support for a provider implementation class for
+ * {@link ResourceBundleProvider}.
  *
  * <p>
- * Resource bundles can be packaged in a named module separated from
- * the <em>caller module</em> loading the resource bundle, i.e. the module
- * calling {@link ResourceBundle#getBundle(String)}.  For the caller module
- * to load a resource bundle "{@code com.example.app.MyResources}"
- * from another module and a service interface named
- * "{@code com.example.app.MyResourcesProvider}",
- * the <em>bundle provider module</em> can provide the implementation class
+ * Resource bundles can be packaged in one or more
+ * named modules, <em>bundle modules</em>.  The <em>consumer</em> of the
+ * resource bundle is the one calling {@link ResourceBundle#getBundle(String)}.
+ * In order for the consumer module to load a resource bundle
+ * "{@code com.example.app.MyResources}" provided by another module,
+ * it will use the {@linkplain java.util.ServiceLoader service loader}
+ * mechanism.  A service interface named "{@code com.example.app.MyResourcesProvider}"
+ * must be defined and a <em>bundle provider module</em> will provide an
+ * implementation class of "{@code com.example.app.MyResourcesProvider}"
  * as follows:
  *
  * <pre><code>
  * import com.example.app.MyResourcesProvider;
  * class MyResourcesProviderImpl extends AbstractResourceBundleProvider
  *     implements MyResourcesProvider
- * {</code>
- *     {@code @Override
+ * {
+ *     protected String toBundleName(String baseName, Locale locale) {
+ *         // return the bundle name per the naming of the resource bundle
+ *         :
+ *     }
+ *
  *     public ResourceBundle getBundle(String baseName, Locale locale) {
  *         // this module only provides bundles in french
  *         if (locale.equals(Locale.FRENCH)) {
@@ -63,7 +73,7 @@
  *         }
  *         return null;
  *     }
- * }}</pre>
+ * }</code></pre>
  *
  * @see <a href="../ResourceBundle.html#bundleprovider">
  *     Resource Bundles in Named Modules</a>
@@ -73,6 +83,9 @@
  * @since 9
  */
 public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider {
+    private static final JavaUtilResourceBundleAccess RB_ACCESS =
+        SharedSecrets.getJavaUtilResourceBundleAccess();
+
     private static final String FORMAT_CLASS = "java.class";
     private static final String FORMAT_PROPERTIES = "java.properties";
 
@@ -112,7 +125,23 @@
 
     /**
      * Returns the bundle name for the given {@code baseName} and {@code
-     * locale}.  This method is called from the default implementation of the
+     * locale} that this provider provides.
+     *
+     * @apiNote
+     * A resource bundle provider may package its resource bundles in the
+     * same package as the base name of the resource bundle if the package
+     * is not split among other named modules.  If there are more than one
+     * bundle providers providing the resource bundle of a given base name,
+     * the resource bundles can be packaged with per-language grouping
+     * or per-region grouping to eliminate the split packages.
+     *
+     * <p>For example, if {@code baseName} is {@code "p.resources.Bundle"} then
+     * the resource bundle name of {@code "p.resources.Bundle"} of
+     * {@code Locale("ja",&nbsp;"",&nbsp;"XX")} and {@code Locale("en")}
+     * could be {@code "p.resources.ja.Bundle_ja_&thinsp;_XX"} and
+     * {@code p.resources.Bundle_en"} respectively
+     *
+     * <p> This method is called from the default implementation of the
      * {@link #getBundle(String, Locale)} method.
      *
      * @implNote The default implementation of this method is the same as the
@@ -126,27 +155,28 @@
      */
     protected String toBundleName(String baseName, Locale locale) {
         return ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT)
-                   .toBundleName(baseName, locale);
+            .toBundleName(baseName, locale);
     }
 
     /**
      * Returns a {@code ResourceBundle} for the given {@code baseName} and
-     * {@code locale}. This method calls the
-     * {@link #toBundleName(String, Locale) toBundleName} method to get the
-     * bundle name for the {@code baseName} and {@code locale}. The formats
-     * specified by the constructor will be searched to find the resource
-     * bundle.
+     * {@code locale}.
      *
      * @implNote
-     * The default implementation of this method will find the resource bundle
-     * local to the module of this provider.
+     * The default implementation of this method calls the
+     * {@link #toBundleName(String, Locale) toBundleName} method to get the
+     * bundle name for the {@code baseName} and {@code locale} and finds the
+     * resource bundle of the bundle name local in the module of this provider.
+     * It will only search the formats specified when this provider was
+     * constructed.
      *
      * @param baseName the base bundle name of the resource bundle, a fully
      *                 qualified class name.
      * @param locale the locale for which the resource bundle should be instantiated
-     * @return {@code ResourceBundle} of the given {@code baseName} and {@code locale},
-     *         or null if no resource bundle is found
-     * @throws NullPointerException if {@code baseName} or {@code locale} is null
+     * @return {@code ResourceBundle} of the given {@code baseName} and
+     *         {@code locale}, or {@code null} if no resource bundle is found
+     * @throws NullPointerException if {@code baseName} or {@code locale} is
+     *         {@code null}
      * @throws UncheckedIOException if any IO exception occurred during resource
      *         bundle loading
      */
@@ -159,13 +189,9 @@
         for (String format : formats) {
             try {
                 if (FORMAT_CLASS.equals(format)) {
-                    PrivilegedAction<ResourceBundle> pa = () ->
-                                    ResourceBundleProviderSupport
-                                         .loadResourceBundle(module, bundleName);
-                    bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                    bundle = loadResourceBundle(module, bundleName);
                 } else if (FORMAT_PROPERTIES.equals(format)) {
-                    bundle = ResourceBundleProviderSupport
-                                 .loadPropertyResourceBundle(module, bundleName);
+                    bundle = loadPropertyResourceBundle(module, bundleName);
                 }
                 if (bundle != null) {
                     break;
@@ -176,4 +202,61 @@
         }
         return bundle;
     }
+
+    /*
+     * Returns the ResourceBundle of .class format if found in the module
+     * of this provider.
+     */
+    private static ResourceBundle loadResourceBundle(Module module, String bundleName)
+    {
+        PrivilegedAction<Class<?>> pa = () -> Class.forName(module, bundleName);
+        Class<?> c = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+        if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
+            @SuppressWarnings("unchecked")
+            Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
+            return RB_ACCESS.newResourceBundle(bundleClass);
+        }
+        return null;
+    }
+
+    /*
+     * Returns the ResourceBundle of .property format if found in the module
+     * of this provider.
+     */
+    private static ResourceBundle loadPropertyResourceBundle(Module module,
+                                                             String bundleName)
+        throws IOException
+    {
+        String resourceName = toResourceName(bundleName, "properties");
+        if (resourceName == null) {
+            return null;
+        }
+
+        PrivilegedAction<InputStream> pa = () -> {
+            try {
+                return module.getResourceAsStream(resourceName);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+        try (InputStream stream = AccessController.doPrivileged(pa)) {
+            if (stream != null) {
+                return new PropertyResourceBundle(stream);
+            } else {
+                return null;
+            }
+        } catch (UncheckedIOException e) {
+            throw e.getCause();
+        }
+    }
+
+    private static String toResourceName(String bundleName, String suffix) {
+        if (bundleName.contains("://")) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
+        sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
+        return sb.toString();
+    }
+
 }
--- a/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,348 +0,0 @@
-/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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 javax.crypto;
-
-import java.util.*;
-import java.util.jar.*;
-import java.io.*;
-import java.net.URL;
-import java.nio.file.*;
-import java.security.*;
-
-import java.security.Provider.Service;
-
-import sun.security.jca.*;
-import sun.security.jca.GetInstance.Instance;
-
-/**
- * This class instantiates implementations of JCE engine classes from
- * providers registered with the java.security.Security object.
- *
- * @author Jan Luehe
- * @author Sharon Liu
- * @since 1.4
- */
-
-final class JceSecurity {
-
-    static final SecureRandom RANDOM = new SecureRandom();
-
-    // The defaultPolicy and exemptPolicy will be set up
-    // in the static initializer.
-    private static CryptoPermissions defaultPolicy = null;
-    private static CryptoPermissions exemptPolicy = null;
-
-    // Map<Provider,?> of the providers we already have verified
-    // value == PROVIDER_VERIFIED is successfully verified
-    // value is failure cause Exception in error case
-    private static final Map<Provider, Object> verificationResults =
-            new IdentityHashMap<>();
-
-    // Map<Provider,?> of the providers currently being verified
-    private static final Map<Provider, Object> verifyingProviders =
-            new IdentityHashMap<>();
-
-    private static final boolean isRestricted;
-
-    /*
-     * Don't let anyone instantiate this.
-     */
-    private JceSecurity() {
-    }
-
-    static {
-        try {
-            AccessController.doPrivileged(
-                new PrivilegedExceptionAction<> () {
-                    @Override
-                    public Void run() throws Exception {
-                        setupJurisdictionPolicies();
-                        return null;
-                    }
-                }
-            );
-
-            isRestricted = defaultPolicy.implies(
-                CryptoAllPermission.INSTANCE) ? false : true;
-        } catch (Exception e) {
-            throw new SecurityException(
-                    "Can not initialize cryptographic mechanism", e);
-        }
-    }
-
-    static Instance getInstance(String type, Class<?> clazz, String algorithm,
-            String provider) throws NoSuchAlgorithmException,
-            NoSuchProviderException {
-        Service s = GetInstance.getService(type, algorithm, provider);
-        Exception ve = getVerificationResult(s.getProvider());
-        if (ve != null) {
-            String msg = "JCE cannot authenticate the provider " + provider;
-            throw (NoSuchProviderException)
-                                new NoSuchProviderException(msg).initCause(ve);
-        }
-        return GetInstance.getInstance(s, clazz);
-    }
-
-    static Instance getInstance(String type, Class<?> clazz, String algorithm,
-            Provider provider) throws NoSuchAlgorithmException {
-        Service s = GetInstance.getService(type, algorithm, provider);
-        Exception ve = JceSecurity.getVerificationResult(provider);
-        if (ve != null) {
-            String msg = "JCE cannot authenticate the provider "
-                + provider.getName();
-            throw new SecurityException(msg, ve);
-        }
-        return GetInstance.getInstance(s, clazz);
-    }
-
-    static Instance getInstance(String type, Class<?> clazz, String algorithm)
-            throws NoSuchAlgorithmException {
-        List<Service> services = GetInstance.getServices(type, algorithm);
-        NoSuchAlgorithmException failure = null;
-        for (Service s : services) {
-            if (canUseProvider(s.getProvider()) == false) {
-                // allow only signed providers
-                continue;
-            }
-            try {
-                Instance instance = GetInstance.getInstance(s, clazz);
-                return instance;
-            } catch (NoSuchAlgorithmException e) {
-                failure = e;
-            }
-        }
-        throw new NoSuchAlgorithmException("Algorithm " + algorithm
-                + " not available", failure);
-    }
-
-    /**
-     * Verify if the JAR at URL codeBase is a signed exempt application
-     * JAR file and returns the permissions bundled with the JAR.
-     *
-     * @throws Exception on error
-     */
-    static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {
-        ProviderVerifier pv = new ProviderVerifier(codeBase, true);
-        pv.verify();
-        return pv.getPermissions();
-    }
-
-    /**
-     * Verify if the JAR at URL codeBase is a signed provider JAR file.
-     *
-     * @throws Exception on error
-     */
-    static void verifyProvider(URL codeBase, Provider p) throws Exception {
-        // Verify the provider JAR file and all
-        // supporting JAR files if there are any.
-        ProviderVerifier pv = new ProviderVerifier(codeBase, p, false);
-        pv.verify();
-    }
-
-    private static final Object PROVIDER_VERIFIED = Boolean.TRUE;
-
-    /*
-     * Verify that the provider JAR files are signed properly, which
-     * means the signer's certificate can be traced back to a
-     * JCE trusted CA.
-     * Return null if ok, failure Exception if verification failed.
-     */
-    static synchronized Exception getVerificationResult(Provider p) {
-        Object o = verificationResults.get(p);
-        if (o == PROVIDER_VERIFIED) {
-            return null;
-        } else if (o != null) {
-            return (Exception)o;
-        }
-        if (verifyingProviders.get(p) != null) {
-            // this method is static synchronized, must be recursion
-            // return failure now but do not save the result
-            return new NoSuchProviderException("Recursion during verification");
-        }
-        try {
-            verifyingProviders.put(p, Boolean.FALSE);
-            URL providerURL = getCodeBase(p.getClass());
-            verifyProvider(providerURL, p);
-            // Verified ok, cache result
-            verificationResults.put(p, PROVIDER_VERIFIED);
-            return null;
-        } catch (Exception e) {
-            verificationResults.put(p, e);
-            return e;
-        } finally {
-            verifyingProviders.remove(p);
-        }
-    }
-
-    // return whether this provider is properly signed and can be used by JCE
-    static boolean canUseProvider(Provider p) {
-        return getVerificationResult(p) == null;
-    }
-
-    // dummy object to represent null
-    private static final URL NULL_URL;
-
-    static {
-        try {
-            NULL_URL = new URL("http://null.oracle.com/");
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    // reference to a Map we use as a cache for codebases
-    private static final Map<Class<?>, URL> codeBaseCacheRef =
-            new WeakHashMap<>();
-
-    /*
-     * Returns the CodeBase for the given class.
-     */
-    static URL getCodeBase(final Class<?> clazz) {
-        synchronized (codeBaseCacheRef) {
-            URL url = codeBaseCacheRef.get(clazz);
-            if (url == null) {
-                url = AccessController.doPrivileged(
-                    new PrivilegedAction<>() {
-                        @Override
-                        public URL run() {
-                            ProtectionDomain pd = clazz.getProtectionDomain();
-                            if (pd != null) {
-                                CodeSource cs = pd.getCodeSource();
-                                if (cs != null) {
-                                    return cs.getLocation();
-                                }
-                            }
-                            return NULL_URL;
-                        }
-                    });
-                codeBaseCacheRef.put(clazz, url);
-            }
-            return (url == NULL_URL) ? null : url;
-        }
-    }
-
-    // This is called from within an doPrivileged block.
-    private static void setupJurisdictionPolicies() throws Exception {
-
-        // Sanity check the crypto.policy Security property.  Single
-        // directory entry, no pseudo-directories (".", "..", leading/trailing
-        // path separators). normalize()/getParent() will help later.
-        String cryptoPolicyProperty = Security.getProperty("crypto.policy");
-        Path cpPath = Paths.get(cryptoPolicyProperty);
-
-        if ((cryptoPolicyProperty == null) ||
-                (cpPath.getNameCount() != 1) ||
-                (cpPath.compareTo(cpPath.getFileName()) != 0)) {
-            throw new SecurityException(
-                "Invalid policy directory name format: " +
-                cryptoPolicyProperty);
-        }
-
-        // Prepend java.home to get the full path.  normalize() in
-        // case an extra "." or ".." snuck in somehow.
-        String javaHomeProperty = System.getProperty("java.home");
-        Path javaHomePolicyPath = Paths.get(javaHomeProperty, "conf",
-                "security", "policy").normalize();
-        Path cryptoPolicyPath = Paths.get(javaHomeProperty, "conf", "security",
-                "policy", cryptoPolicyProperty).normalize();
-
-        if (cryptoPolicyPath.getParent().compareTo(javaHomePolicyPath) != 0) {
-            throw new SecurityException(
-                "Invalid cryptographic jurisdiction policy directory path: " +
-                cryptoPolicyProperty);
-        }
-
-        if (!Files.isDirectory(cryptoPolicyPath)
-                || !Files.isReadable(cryptoPolicyPath)) {
-            throw new SecurityException(
-                "Can't read cryptographic policy directory: " +
-                cryptoPolicyProperty);
-        }
-
-        try (DirectoryStream<Path> stream = Files.newDirectoryStream(
-                cryptoPolicyPath, "{default,exempt}_*.policy")) {
-            for (Path entry : stream) {
-                try (InputStream is = new BufferedInputStream(
-                        Files.newInputStream(entry))) {
-                    String filename = entry.getFileName().toString();
-
-                    CryptoPermissions tmpPerms = new CryptoPermissions();
-                    tmpPerms.load(is);
-
-                    if (filename.startsWith("default_")) {
-                        // Did we find a default perms?
-                        defaultPolicy = ((defaultPolicy == null) ? tmpPerms :
-                                defaultPolicy.getMinimum(tmpPerms));
-                    } else if (filename.startsWith("exempt_")) {
-                        // Did we find a exempt perms?
-                        exemptPolicy = ((exemptPolicy == null) ? tmpPerms :
-                                exemptPolicy.getMinimum(tmpPerms));
-                    } else {
-                        // This should never happen.  newDirectoryStream
-                        // should only throw return "{default,exempt}_*.policy"
-                        throw new SecurityException(
-                            "Unexpected jurisdiction policy files in : " +
-                            cryptoPolicyProperty);
-                    }
-                } catch (Exception e) {
-                    throw new SecurityException(
-                        "Couldn't parse jurisdiction policy files in: " +
-                        cryptoPolicyProperty);
-                }
-            }
-        } catch (DirectoryIteratorException ex) {
-            // I/O error encountered during the iteration,
-            // the cause is an IOException
-            throw new SecurityException(
-                "Couldn't iterate through the jurisdiction policy files: " +
-                cryptoPolicyProperty);
-        }
-
-        // Must have a default policy
-        if ((defaultPolicy == null) || defaultPolicy.isEmpty()) {
-            throw new SecurityException(
-                "Missing mandatory jurisdiction policy files: " +
-                cryptoPolicyProperty);
-        }
-
-        // If there was an empty exempt policy file, ignore it.
-        if ((exemptPolicy != null) && exemptPolicy.isEmpty()) {
-            exemptPolicy = null;
-        }
-    }
-
-    static CryptoPermissions getDefaultPolicy() {
-        return defaultPolicy;
-    }
-
-    static CryptoPermissions getExemptPolicy() {
-        return exemptPolicy;
-    }
-
-    static boolean isRestricted() {
-        return isRestricted;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java.template	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.
+ */
+
+/*
+ * README README README README README README README README README
+ *
+ * This file is the template for generating the JceSecurity.java source
+ * file.
+ *
+ * In the current jdk builds, this file is first preprocessed to replace
+ * @@JCE_DEFAULT_POLICY@ [sic] with "limited" or "unlimited" which is
+ * determined by the $(UNLIMTED_CRYPTO) make variable.  This variable is
+ * set by top-level configure script, using either
+ * --disable-unlimited-crypto or --enable-unlimited-crypto [default].
+ *
+ * Since this file is a generated source, incremental changes to
+ * this file require regenerating the source.  Compilation options:
+ *
+ *     (fewer dependencies/"faster" ones first)
+ *
+ * 1.  make JDK_FILTER=javax/crypto java.base-gensrc-only java.base-java-only
+ * 2.  make java.base-gensrc-only java.base-java-only
+ * 3.  make java.base-gensrc-only java.base-only
+ * 4.  make java.base-only
+ * 5.  make
+ */
+
+package javax.crypto;
+
+import java.util.*;
+import java.io.*;
+import java.net.URL;
+import java.nio.file.*;
+import java.security.*;
+
+import java.security.Provider.Service;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+import sun.security.util.Debug;
+
+/**
+ * This class instantiates implementations of JCE engine classes from
+ * providers registered with the java.security.Security object.
+ *
+ * @author Jan Luehe
+ * @author Sharon Liu
+ * @since 1.4
+ */
+
+final class JceSecurity {
+  
+  	
+    private static final Debug debug = Debug.getInstance("jca");
+
+    static final SecureRandom RANDOM = new SecureRandom();
+
+    // The defaultPolicy and exemptPolicy will be set up
+    // in the static initializer.
+    private static CryptoPermissions defaultPolicy = null;
+    private static CryptoPermissions exemptPolicy = null;
+
+    // Map<Provider,?> of the providers we already have verified
+    // value == PROVIDER_VERIFIED is successfully verified
+    // value is failure cause Exception in error case
+    private static final Map<Provider, Object> verificationResults =
+            new IdentityHashMap<>();
+
+    // Map<Provider,?> of the providers currently being verified
+    private static final Map<Provider, Object> verifyingProviders =
+            new IdentityHashMap<>();
+
+    private static final boolean isRestricted;
+
+    /*
+     * Don't let anyone instantiate this.
+     */
+    private JceSecurity() {
+    }
+
+    static {
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<> () {
+                    @Override
+                    public Void run() throws Exception {
+                        setupJurisdictionPolicies();
+                        return null;
+                    }
+                }
+            );
+
+            isRestricted = defaultPolicy.implies(
+                CryptoAllPermission.INSTANCE) ? false : true;
+        } catch (Exception e) {
+            throw new SecurityException(
+                    "Can not initialize cryptographic mechanism", e);
+        }
+    }
+
+    static Instance getInstance(String type, Class<?> clazz, String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Service s = GetInstance.getService(type, algorithm, provider);
+        Exception ve = getVerificationResult(s.getProvider());
+        if (ve != null) {
+            String msg = "JCE cannot authenticate the provider " + provider;
+            throw (NoSuchProviderException)
+                                new NoSuchProviderException(msg).initCause(ve);
+        }
+        return GetInstance.getInstance(s, clazz);
+    }
+
+    static Instance getInstance(String type, Class<?> clazz, String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Service s = GetInstance.getService(type, algorithm, provider);
+        Exception ve = JceSecurity.getVerificationResult(provider);
+        if (ve != null) {
+            String msg = "JCE cannot authenticate the provider "
+                + provider.getName();
+            throw new SecurityException(msg, ve);
+        }
+        return GetInstance.getInstance(s, clazz);
+    }
+
+    static Instance getInstance(String type, Class<?> clazz, String algorithm)
+            throws NoSuchAlgorithmException {
+        List<Service> services = GetInstance.getServices(type, algorithm);
+        NoSuchAlgorithmException failure = null;
+        for (Service s : services) {
+            if (canUseProvider(s.getProvider()) == false) {
+                // allow only signed providers
+                continue;
+            }
+            try {
+                Instance instance = GetInstance.getInstance(s, clazz);
+                return instance;
+            } catch (NoSuchAlgorithmException e) {
+                failure = e;
+            }
+        }
+        throw new NoSuchAlgorithmException("Algorithm " + algorithm
+                + " not available", failure);
+    }
+
+    /**
+     * Verify if the JAR at URL codeBase is a signed exempt application
+     * JAR file and returns the permissions bundled with the JAR.
+     *
+     * @throws Exception on error
+     */
+    static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {
+        ProviderVerifier pv = new ProviderVerifier(codeBase, true);
+        pv.verify();
+        return pv.getPermissions();
+    }
+
+    /**
+     * Verify if the JAR at URL codeBase is a signed provider JAR file.
+     *
+     * @throws Exception on error
+     */
+    static void verifyProvider(URL codeBase, Provider p) throws Exception {
+        // Verify the provider JAR file and all
+        // supporting JAR files if there are any.
+        ProviderVerifier pv = new ProviderVerifier(codeBase, p, false);
+        pv.verify();
+    }
+
+    private static final Object PROVIDER_VERIFIED = Boolean.TRUE;
+
+    /*
+     * Verify that the provider JAR files are signed properly, which
+     * means the signer's certificate can be traced back to a
+     * JCE trusted CA.
+     * Return null if ok, failure Exception if verification failed.
+     */
+    static synchronized Exception getVerificationResult(Provider p) {
+        Object o = verificationResults.get(p);
+        if (o == PROVIDER_VERIFIED) {
+            return null;
+        } else if (o != null) {
+            return (Exception)o;
+        }
+        if (verifyingProviders.get(p) != null) {
+            // this method is static synchronized, must be recursion
+            // return failure now but do not save the result
+            return new NoSuchProviderException("Recursion during verification");
+        }
+        try {
+            verifyingProviders.put(p, Boolean.FALSE);
+            URL providerURL = getCodeBase(p.getClass());
+            verifyProvider(providerURL, p);
+            // Verified ok, cache result
+            verificationResults.put(p, PROVIDER_VERIFIED);
+            return null;
+        } catch (Exception e) {
+            verificationResults.put(p, e);
+            return e;
+        } finally {
+            verifyingProviders.remove(p);
+        }
+    }
+
+    // return whether this provider is properly signed and can be used by JCE
+    static boolean canUseProvider(Provider p) {
+        return getVerificationResult(p) == null;
+    }
+
+    // dummy object to represent null
+    private static final URL NULL_URL;
+
+    static {
+        try {
+            NULL_URL = new URL("http://null.oracle.com/");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // reference to a Map we use as a cache for codebases
+    private static final Map<Class<?>, URL> codeBaseCacheRef =
+            new WeakHashMap<>();
+
+    /*
+     * Returns the CodeBase for the given class.
+     */
+    static URL getCodeBase(final Class<?> clazz) {
+        synchronized (codeBaseCacheRef) {
+            URL url = codeBaseCacheRef.get(clazz);
+            if (url == null) {
+                url = AccessController.doPrivileged(
+                    new PrivilegedAction<>() {
+                        @Override
+                        public URL run() {
+                            ProtectionDomain pd = clazz.getProtectionDomain();
+                            if (pd != null) {
+                                CodeSource cs = pd.getCodeSource();
+                                if (cs != null) {
+                                    return cs.getLocation();
+                                }
+                            }
+                            return NULL_URL;
+                        }
+                    });
+                codeBaseCacheRef.put(clazz, url);
+            }
+            return (url == NULL_URL) ? null : url;
+        }
+    }
+
+    // This is called from within an doPrivileged block.
+    private static void setupJurisdictionPolicies() throws Exception {
+
+        // Sanity check the crypto.policy Security property.  Single
+        // directory entry, no pseudo-directories (".", "..", leading/trailing
+        // path separators). normalize()/getParent() will help later.
+        String cryptoPolicyProperty = Security.getProperty("crypto.policy");
+
+        /*
+         * In case no property is present, rather than fail catastrophically,
+         * we at least try for a "sane" value, which is what we were
+         * built with.  We first preprocess this file to plug in that
+         * value, then compile the result gensrc.
+         *
+         * Log the warning first.
+         */
+        if (cryptoPolicyProperty == null) {
+            cryptoPolicyProperty = "@@JCE_DEFAULT_POLICY@@";
+            if (debug != null) {
+                debug.println(
+                    "Security Property 'crypto.policy' not found: "
+                    + "using '" + cryptoPolicyProperty + "' as fallback");
+            }
+        }
+
+        Path cpPath = Paths.get(cryptoPolicyProperty);
+
+        if ((cpPath.getNameCount() != 1) ||
+                (cpPath.compareTo(cpPath.getFileName()) != 0)) {
+            throw new SecurityException(
+                "Invalid policy directory name format: " +
+                cryptoPolicyProperty);
+        }
+
+        // Prepend java.home to get the full path.  normalize() in
+        // case an extra "." or ".." snuck in somehow.
+        String javaHomeProperty = System.getProperty("java.home");
+        Path javaHomePolicyPath = Paths.get(javaHomeProperty, "conf",
+                "security", "policy").normalize();
+        Path cryptoPolicyPath = Paths.get(javaHomeProperty, "conf", "security",
+                "policy", cryptoPolicyProperty).normalize();
+
+        if (cryptoPolicyPath.getParent().compareTo(javaHomePolicyPath) != 0) {
+            throw new SecurityException(
+                "Invalid cryptographic jurisdiction policy directory path: " +
+                cryptoPolicyProperty);
+        }
+
+        if (!Files.isDirectory(cryptoPolicyPath)
+                || !Files.isReadable(cryptoPolicyPath)) {
+            throw new SecurityException(
+                "Can't read cryptographic policy directory: " +
+                cryptoPolicyProperty);
+        }
+
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(
+                cryptoPolicyPath, "{default,exempt}_*.policy")) {
+            for (Path entry : stream) {
+                try (InputStream is = new BufferedInputStream(
+                        Files.newInputStream(entry))) {
+                    String filename = entry.getFileName().toString();
+
+                    CryptoPermissions tmpPerms = new CryptoPermissions();
+                    tmpPerms.load(is);
+
+                    if (filename.startsWith("default_")) {
+                        // Did we find a default perms?
+                        defaultPolicy = ((defaultPolicy == null) ? tmpPerms :
+                                defaultPolicy.getMinimum(tmpPerms));
+                    } else if (filename.startsWith("exempt_")) {
+                        // Did we find a exempt perms?
+                        exemptPolicy = ((exemptPolicy == null) ? tmpPerms :
+                                exemptPolicy.getMinimum(tmpPerms));
+                    } else {
+                        // This should never happen.  newDirectoryStream
+                        // should only throw return "{default,exempt}_*.policy"
+                        throw new SecurityException(
+                            "Unexpected jurisdiction policy files in : " +
+                            cryptoPolicyProperty);
+                    }
+                } catch (Exception e) {
+                    throw new SecurityException(
+                        "Couldn't parse jurisdiction policy files in: " +
+                        cryptoPolicyProperty);
+                }
+            }
+        } catch (DirectoryIteratorException ex) {
+            // I/O error encountered during the iteration,
+            // the cause is an IOException
+            throw new SecurityException(
+                "Couldn't iterate through the jurisdiction policy files: " +
+                cryptoPolicyProperty);
+        }
+
+        // Must have a default policy
+        if ((defaultPolicy == null) || defaultPolicy.isEmpty()) {
+            throw new SecurityException(
+                "Missing mandatory jurisdiction policy files: " +
+                cryptoPolicyProperty);
+        }
+
+        // If there was an empty exempt policy file, ignore it.
+        if ((exemptPolicy != null) && exemptPolicy.isEmpty()) {
+            exemptPolicy = null;
+        }
+    }
+
+    static CryptoPermissions getDefaultPolicy() {
+        return defaultPolicy;
+    }
+
+    static CryptoPermissions getExemptPolicy() {
+        return exemptPolicy;
+    }
+
+    static boolean isRestricted() {
+        return isRestricted;
+    }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -115,7 +115,7 @@
     private FileSystem newFileSystem(String targetHome, URI uri, Map<String, ?> env)
             throws IOException {
         Objects.requireNonNull(targetHome);
-        Path jrtfs = FileSystems.getDefault().getPath(targetHome, JRT_FS_JAR);
+        Path jrtfs = FileSystems.getDefault().getPath(targetHome, "lib", JRT_FS_JAR);
         if (Files.notExists(jrtfs)) {
             throw new IOException(jrtfs.toString() + " not exist");
         }
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java	Wed Jul 05 22:32:06 2017 +0200
@@ -113,12 +113,16 @@
         if (cs == null)
             return System.getProperty("java.home");
 
-        // assume loaded from $TARGETJDK/jrt-fs.jar
+        // assume loaded from $TARGETJDK/lib/jrt-fs.jar
         URL url = cs.getLocation();
         if (!url.getProtocol().equalsIgnoreCase("file"))
-            throw new RuntimeException(url + " loaded in unexpected way");
+            throw new InternalError(url + " loaded in unexpected way");
         try {
-            return Paths.get(url.toURI()).getParent().toString();
+            Path lib = Paths.get(url.toURI()).getParent();
+            if (!lib.getFileName().toString().equals("lib"))
+                throw new InternalError(url + " unexpected path");
+
+            return lib.getParent().toString();
         } catch (URISyntaxException e) {
             throw new InternalError(e);
         }
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -71,8 +71,8 @@
     private static final ServicesCatalog SERVICES_CATALOG = ServicesCatalog.create();
 
     // ClassLoaderValue map for boot class loader
-    private static final ConcurrentHashMap<?, ?> CLASS_LOADER_VALUE_MAP =
-        new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<?, ?> CLASS_LOADER_VALUE_MAP
+        = new ConcurrentHashMap<>();
 
     /**
      * Returns the unnamed module for the boot loader.
@@ -111,14 +111,27 @@
     }
 
     /**
-     * Returns a URL to a resource in a named module defined to the boot loader.
+     * Loads the Class object with the given name in the given module
+     * defined to the boot loader. Returns {@code null} if not found.
+     */
+    public static Class<?> loadClass(Module module, String name) {
+        Class<?> c = loadClassOrNull(name);
+        if (c != null && c.getModule() == module) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a URL to a resource in a module defined to the boot loader.
      */
     public static URL findResource(String mn, String name) throws IOException {
         return ClassLoaders.bootLoader().findResource(mn, name);
     }
 
     /**
-     * Returns an input stream to a resource in a named module defined to the
+     * Returns an input stream to a resource in a module defined to the
      * boot loader.
      */
     public static InputStream findResourceAsStream(String mn, String name)
@@ -128,9 +141,8 @@
     }
 
     /**
-     * Returns the URL to the given resource if the resource can be located
-     * on the boot class path. This method does not locate a resource in any
-     * of the named modules defined to the boot loader.
+     * Returns the URL to the given resource in any of the modules
+     * defined to the boot loader and the boot class path.
      */
     public static URL findResource(String name) {
         return ClassLoaders.bootLoader().findResource(name);
@@ -138,8 +150,7 @@
 
     /**
      * Returns an Iterator to iterate over the resources of the given name
-     * on the boot class path. This method does not locate resources in any
-     * of the named modules defined to the boot loader.
+     * in any of the modules defined to the boot loader.
      */
     public static Enumeration<URL> findResources(String name) throws IOException {
         return ClassLoaders.bootLoader().findResources(name);
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,8 +29,10 @@
 import java.io.FilePermission;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleReference;
 import java.lang.module.ModuleReader;
+import java.lang.ref.SoftReference;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
@@ -91,7 +93,7 @@
 {
     static {
         if (!ClassLoader.registerAsParallelCapable())
-            throw new InternalError();
+            throw new InternalError("Unable to register as parallel capable");
     }
 
     // parent ClassLoader
@@ -117,7 +119,7 @@
             if (mref.location().isPresent()) {
                 try {
                     url = mref.location().get().toURL();
-                } catch (MalformedURLException e) { }
+                } catch (MalformedURLException | IllegalArgumentException e) { }
             }
             this.loader = loader;
             this.mref = mref;
@@ -141,6 +143,9 @@
     // maps a module reference to a module reader
     private final Map<ModuleReference, ModuleReader> moduleToReader;
 
+    // cache of resource name -> list of URLs.
+    // used only for resources that are not in module packages
+    private volatile SoftReference<Map<String, List<URL>>> resourceCache;
 
     /**
      * Create a new instance.
@@ -161,6 +166,8 @@
      * the types in the module visible.
      */
     public void loadModule(ModuleReference mref) {
+        assert !VM.isModuleSystemInited();
+
         String mn = mref.descriptor().name();
         if (nameToModule.putIfAbsent(mn, mref) != null) {
             throw new InternalError(mn + " already defined to this loader");
@@ -195,32 +202,20 @@
      */
     @Override
     public URL findResource(String mn, String name) throws IOException {
-        ModuleReference mref = nameToModule.get(mn);
-        if (mref == null)
-            return null;   // not defined to this class loader
-
-        URL url;
+        URL url = null;
 
-        try {
-            url = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<URL>() {
-                    @Override
-                    public URL run() throws IOException {
-                        URI u = moduleReaderFor(mref).find(name).orElse(null);
-                        if (u != null) {
-                            try {
-                                return u.toURL();
-                            } catch (MalformedURLException e) { }
-                        }
-                        return null;
-                    }
-                });
-        } catch (PrivilegedActionException pae) {
-            throw (IOException) pae.getCause();
+        if (mn != null) {
+            // find in module
+            ModuleReference mref = nameToModule.get(mn);
+            if (mref != null) {
+                url = findResource(mref, name);
+            }
+        } else {
+            // find on class path
+            url = findResourceOnClassPath(name);
         }
 
-        // check access to the URL
-        return checkURL(url);
+        return checkURL(url);  // check access before returning
     }
 
     /**
@@ -232,70 +227,234 @@
     {
         // Need URL to resource when running with a security manager so that
         // the right permission check is done.
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-
+        if (System.getSecurityManager() != null || mn == null) {
             URL url = findResource(mn, name);
             return (url != null) ? url.openStream() : null;
-
-        } else {
-
-            ModuleReference mref = nameToModule.get(mn);
-            if (mref == null)
-                return null;   // not defined to this class loader
+        }
 
-            try {
-                return AccessController.doPrivileged(
-                    new PrivilegedExceptionAction<InputStream>() {
-                        @Override
-                        public InputStream run() throws IOException {
-                            return moduleReaderFor(mref).open(name).orElse(null);
-                        }
-                    });
-            } catch (PrivilegedActionException pae) {
-                throw (IOException) pae.getCause();
-            }
-        }
-    }
-
-    /**
-     * Finds the resource with the given name on the class path of this class
-     * loader.
-     */
-    @Override
-    public URL findResource(String name) {
-        if (ucp != null) {
-            PrivilegedAction<URL> pa = () -> ucp.findResource(name, false);
-            URL url = AccessController.doPrivileged(pa);
-            return checkURL(url);
+        // find in module defined to this loader, no security manager
+        ModuleReference mref = nameToModule.get(mn);
+        if (mref != null) {
+            return moduleReaderFor(mref).open(name).orElse(null);
         } else {
             return null;
         }
     }
 
     /**
+     * Finds a resource with the given name in the modules defined to this
+     * class loader or its class path.
+     */
+    @Override
+    public URL findResource(String name) {
+        String pn = ResourceHelper.getPackageName(name);
+        LoadedModule module = packageToModule.get(pn);
+        if (module != null) {
+
+            // resource is in a package of a module defined to this loader
+            if (module.loader() == this
+                && (name.endsWith(".class") || isOpen(module.mref(), pn))) {
+                try {
+                    return findResource(module.name(), name); // checks URL
+                } catch (IOException ioe) {
+                    return null;
+                }
+            }
+
+        } else {
+
+            // not in a module package but may be in module defined to this loader
+            try {
+                List<URL> urls = findMiscResource(name);
+                if (!urls.isEmpty()) {
+                    URL url = urls.get(0);
+                    if (url != null) {
+                        return checkURL(url); // check access before returning
+                    }
+                }
+            } catch (IOException ioe) {
+                return null;
+            }
+
+        }
+
+        // search class path
+        URL url = findResourceOnClassPath(name);
+        return checkURL(url);
+    }
+
+    /**
      * Returns an enumeration of URL objects to all the resources with the
-     * given name on the class path of this class loader.
+     * given name in modules defined to this class loader or on the class
+     * path of this loader.
      */
     @Override
     public Enumeration<URL> findResources(String name) throws IOException {
-        if (ucp != null) {
-            List<URL> result = new ArrayList<>();
-            PrivilegedAction<Enumeration<URL>> pa = () -> ucp.findResources(name, false);
-            Enumeration<URL> e = AccessController.doPrivileged(pa);
-            while (e.hasMoreElements()) {
-                URL url = checkURL(e.nextElement());
+        List<URL> checked = new ArrayList<>();  // list of checked URLs
+
+        String pn = ResourceHelper.getPackageName(name);
+        LoadedModule module = packageToModule.get(pn);
+        if (module != null) {
+
+            // resource is in a package of a module defined to this loader
+            if (module.loader() == this
+                && (name.endsWith(".class") || isOpen(module.mref(), pn))) {
+                URL url = findResource(module.name(), name);  // checks URL
                 if (url != null) {
-                    result.add(url);
+                    checked.add(url);
+                }
+            }
+
+        } else {
+            // not in a package of a module defined to this loader
+            for (URL url : findMiscResource(name)) {
+                url = checkURL(url);
+                if (url != null) {
+                    checked.add(url);
                 }
             }
-            return Collections.enumeration(result); // checked URLs
+        }
+
+        // search class path
+        Enumeration<URL> e = findResourcesOnClassPath(name);
+        while (e.hasMoreElements()) {
+            URL url = checkURL(e.nextElement());
+            if (url != null) {
+                checked.add(url);
+            }
+        }
+
+        return Collections.enumeration(checked);
+    }
+
+    /**
+     * Returns the list of URLs to a "miscellaneous" resource in modules
+     * defined to this loader. A miscellaneous resource is not in a module
+     * package, e.g. META-INF/services/p.S.
+     *
+     * The cache used by this method avoids repeated searching of all modules.
+     */
+    private List<URL> findMiscResource(String name) throws IOException {
+        SoftReference<Map<String, List<URL>>> ref = this.resourceCache;
+        Map<String, List<URL>> map = (ref != null) ? ref.get() : null;
+        if (map != null) {
+            List<URL> urls = map.get(name);
+            if (urls != null)
+                return urls;
+        }
+
+        // search all modules for the resource
+        List<URL> urls;
+        try {
+            urls = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<>() {
+                    @Override
+                    public List<URL> run() throws IOException {
+                        List<URL> result = new ArrayList<>();
+                        for (ModuleReference mref : nameToModule.values()) {
+                            URI u = moduleReaderFor(mref).find(name).orElse(null);
+                            if (u != null) {
+                                try {
+                                    result.add(u.toURL());
+                                } catch (MalformedURLException |
+                                         IllegalArgumentException e) {
+                                }
+                            }
+                        }
+                        return result;
+                    }
+                });
+        } catch (PrivilegedActionException pae) {
+            throw (IOException) pae.getCause();
+        }
+
+        // only cache resources after all modules have been defined
+        if (VM.isModuleSystemInited()) {
+            if (map == null) {
+                map = new ConcurrentHashMap<>();
+                this.resourceCache = new SoftReference<>(map);
+            }
+            if (urls.isEmpty())
+                urls = Collections.emptyList();
+            map.putIfAbsent(name, urls);
+        }
+        return urls;
+    }
+
+    /**
+     * Returns the URL to a resource in a module or {@code null} if not found.
+     */
+    private URL findResource(ModuleReference mref, String name) throws IOException {
+        URI u;
+        if (System.getSecurityManager() == null) {
+            u = moduleReaderFor(mref).find(name).orElse(null);
         } else {
+            try {
+                u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () {
+                    @Override
+                    public URI run() throws IOException {
+                        return moduleReaderFor(mref).find(name).orElse(null);
+                    }
+                });
+            } catch (PrivilegedActionException pae) {
+                throw (IOException) pae.getCause();
+            }
+        }
+        if (u != null) {
+            try {
+                return u.toURL();
+            } catch (MalformedURLException | IllegalArgumentException e) { }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the URL to a resource in a module. Returns {@code null} if not found
+     * or an I/O error occurs.
+     */
+    private URL findResourceOrNull(ModuleReference mref, String name) {
+        try {
+            return findResource(mref, name);
+        } catch (IOException ignore) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a URL to a resource on the class path.
+     */
+    private URL findResourceOnClassPath(String name) {
+        if (ucp != null) {
+            if (System.getSecurityManager() == null) {
+                return ucp.findResource(name, false);
+            } else {
+                PrivilegedAction<URL> pa = () -> ucp.findResource(name, false);
+                return AccessController.doPrivileged(pa);
+            }
+        } else {
+            // no class path
+            return null;
+        }
+    }
+
+    /**
+     * Returns the URLs of all resources of the given name on the class path.
+     */
+    private Enumeration<URL> findResourcesOnClassPath(String name) {
+        if (ucp != null) {
+            if (System.getSecurityManager() == null) {
+                return ucp.findResources(name, false);
+            } else {
+                PrivilegedAction<Enumeration<URL>> pa;
+                pa = () -> ucp.findResources(name, false);
+                return AccessController.doPrivileged(pa);
+            }
+        } else {
+            // no class path
             return Collections.emptyEnumeration();
         }
     }
 
-
     // -- finding/loading classes
 
     /**
@@ -335,24 +494,30 @@
     }
 
     /**
-     * Finds the class with the specified binary name in a given module.
-     * This method returns {@code null} if the class cannot be found.
+     * Finds the class with the specified binary name in a module.
+     * This method returns {@code null} if the class cannot be found
+     * or not defined in the specified module.
      */
     @Override
     protected Class<?> findClass(String mn, String cn) {
-        ModuleReference mref = nameToModule.get(mn);
-        if (mref == null)
-            return null;   // not defined to this class loader
+        if (mn != null) {
+            // find the candidate module for this class
+            LoadedModule loadedModule = findLoadedModule(mn, cn);
+            if (loadedModule == null) {
+                return null;
+            }
 
-        // find the candidate module for this class
-        LoadedModule loadedModule = findLoadedModule(cn);
-        if (loadedModule == null || !loadedModule.name().equals(mn)) {
-            return null;   // module name does not match
+            // attempt to load class in module defined to this loader
+            assert loadedModule.loader() == this;
+            return findClassInModuleOrNull(loadedModule, cn);
         }
 
-        // attempt to load class in module defined to this loader
-        assert loadedModule.loader() == this;
-        return findClassInModuleOrNull(loadedModule, cn);
+        // search class path
+        if (ucp != null) {
+            return findClassOnClassPathOrNull(cn);
+        }
+
+        return null;
     }
 
     /**
@@ -441,14 +606,33 @@
     }
 
     /**
+     * Find the candidate loaded module for the given class name
+     * in the named module.  Returns {@code null} if the named module
+     * is not defined to this class loader or does not contain
+     * the API package for the class.
+     */
+    private LoadedModule findLoadedModule(String mn, String cn) {
+        LoadedModule loadedModule = findLoadedModule(cn);
+        if (loadedModule != null && mn.equals(loadedModule.name())) {
+            return loadedModule;
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * Finds the class with the specified binary name if in a module
      * defined to this ClassLoader.
      *
      * @return the resulting Class or {@code null} if not found
      */
     private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) {
-        PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
-        return AccessController.doPrivileged(pa);
+        if (System.getSecurityManager() == null) {
+            return defineClass(cn, loadedModule);
+        } else {
+            PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
+            return AccessController.doPrivileged(pa);
+        }
     }
 
     /**
@@ -457,10 +641,21 @@
      * @return the resulting Class or {@code null} if not found
      */
     private Class<?> findClassOnClassPathOrNull(String cn) {
-        return AccessController.doPrivileged(
-            new PrivilegedAction<Class<?>>() {
+        String path = cn.replace('.', '/').concat(".class");
+        if (System.getSecurityManager() == null) {
+            Resource res = ucp.getResource(path, false);
+            if (res != null) {
+                try {
+                    return defineClass(cn, res);
+                } catch (IOException ioe) {
+                    // TBD on how I/O errors should be propagated
+                }
+            }
+            return null;
+        } else {
+            // avoid use of lambda here
+            PrivilegedAction<Class<?>> pa = new PrivilegedAction<>() {
                 public Class<?> run() {
-                    String path = cn.replace('.', '/').concat(".class");
                     Resource res = ucp.getResource(path, false);
                     if (res != null) {
                         try {
@@ -471,7 +666,9 @@
                     }
                     return null;
                 }
-            });
+            };
+            return AccessController.doPrivileged(pa);
+        }
     }
 
     /**
@@ -662,13 +859,13 @@
                 sealBase = url;
         }
         return definePackage(pn,
-                             specTitle,
-                             specVersion,
-                             specVendor,
-                             implTitle,
-                             implVersion,
-                             implVendor,
-                             sealBase);
+                specTitle,
+                specVersion,
+                specVendor,
+                implTitle,
+                implVersion,
+                implVendor,
+                sealBase);
     }
 
     /**
@@ -760,6 +957,27 @@
     };
 
     /**
+     * Returns true if the given module opens the given package
+     * unconditionally.
+     *
+     * @implNote This method currently iterates over each of the open
+     * packages. This will be replaced once the ModuleDescriptor.Opens
+     * API is updated.
+     */
+    private boolean isOpen(ModuleReference mref, String pn) {
+        ModuleDescriptor descriptor = mref.descriptor();
+        if (descriptor.isOpen())
+            return true;
+        for (ModuleDescriptor.Opens opens : descriptor.opens()) {
+            String source = opens.source();
+            if (!opens.isQualified() && source.equals(pn)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Checks access to the given URL. We use URLClassPath for consistent
      * checking with java.net.URLClassLoader.
      */
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -48,13 +48,19 @@
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.security.SecureClassLoader;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Stream;
 
+import jdk.internal.misc.SharedSecrets;
+
 
 /**
  * A class loader that loads classes and resources from a collection of
@@ -119,7 +125,7 @@
             if (mref.location().isPresent()) {
                 try {
                     url = mref.location().get().toURL();
-                } catch (MalformedURLException e) { }
+                } catch (MalformedURLException | IllegalArgumentException e) { }
             }
             this.mref = mref;
             this.url = url;
@@ -141,7 +147,7 @@
                   LoaderPool pool,
                   ClassLoader parent)
     {
-        super(parent);
+        super("Loader-" + resolvedModule.name(), parent);
 
         this.pool = pool;
         this.parent = parent;
@@ -200,12 +206,12 @@
      * @param cf the Configuration containing at least modules to be defined to
      *           this class loader
      *
-     * @param parentLayer the parent Layer
+     * @param parentLayers the parent Layers
      */
-    public Loader initRemotePackageMap(Configuration cf, Layer parentLayer) {
-
+    public Loader initRemotePackageMap(Configuration cf,
+                                       List<Layer> parentLayers)
+    {
         for (String name : nameToModule.keySet()) {
-
             ResolvedModule resolvedModule = cf.findModule(name).get();
             assert resolvedModule.configuration() == cf;
 
@@ -228,17 +234,15 @@
 
                 } else {
 
-                    // find the layer contains the module that is read
-                    Layer layer = parentLayer;
-                    while (layer != null) {
-                        if (layer.configuration() == other.configuration()) {
-                            break;
-                        }
-                        layer = layer.parent().orElse(null);
-                    }
-                    assert layer != null;
+                    // find the layer for the target module
+                    Layer layer = parentLayers.stream()
+                        .map(parent -> findLayer(parent, other.configuration()))
+                        .flatMap(Optional::stream)
+                        .findAny()
+                        .orElseThrow(() ->
+                            new InternalError("Unable to find parent layer"));
 
-                    // find the class loader for the module in the layer
+                    // find the class loader for the module
                     // For now we use the platform loader for modules defined to the
                     // boot loader
                     assert layer.findModule(mn).isPresent();
@@ -268,7 +272,6 @@
                             throw new IllegalArgumentException("Package "
                                 + pn + " cannot be imported from multiple loaders");
                         }
-
                     }
                 }
             }
@@ -279,6 +282,17 @@
     }
 
     /**
+     * Find the layer corresponding to the given configuration in the tree
+     * of layers rooted at the given parent.
+     */
+    private Optional<Layer> findLayer(Layer parent, Configuration cf) {
+        return SharedSecrets.getJavaLangReflectModuleAccess().layers(parent)
+                .filter(l -> l.configuration() == cf)
+                .findAny();
+    }
+
+
+    /**
      * Returns the loader pool that this loader is in or {@code null} if this
      * loader is not in a loader pool.
      */
@@ -296,12 +310,14 @@
      */
     @Override
     protected URL findResource(String mn, String name) throws IOException {
-        ModuleReference mref = nameToModule.get(mn);
+        ModuleReference mref = (mn != null) ? nameToModule.get(mn) : null;
         if (mref == null)
             return null;   // not defined to this class loader
 
+        // locate resource
+        URL url = null;
         try {
-            return AccessController.doPrivileged(
+            url = AccessController.doPrivileged(
                 new PrivilegedExceptionAction<URL>() {
                     @Override
                     public URL run() throws IOException {
@@ -309,16 +325,89 @@
                         if (ouri.isPresent()) {
                             try {
                                 return ouri.get().toURL();
-                            } catch (MalformedURLException e) { }
+                            } catch (MalformedURLException |
+                                     IllegalArgumentException e) { }
                         }
                         return null;
                     }
-                }, acc);
+                });
         } catch (PrivilegedActionException pae) {
             throw (IOException) pae.getCause();
-        } catch (SecurityException se) {
-            return null;
+        }
+
+        // check access with permissions restricted by ACC
+        if (url != null && System.getSecurityManager() != null) {
+            try {
+                URL urlToCheck = url;
+                url = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<URL>() {
+                        @Override
+                        public URL run() throws IOException {
+                            return URLClassPath.checkURL(urlToCheck);
+                        }
+                    }, acc);
+            } catch (PrivilegedActionException pae) {
+                url = null;
+            }
         }
+
+        return url;
+    }
+
+    @Override
+    public URL findResource(String name) {
+        URL url = null;
+        String pn = ResourceHelper.getPackageName(name);
+        LoadedModule module = localPackageToModule.get(pn);
+        if (module != null) {
+            if (name.endsWith(".class") || isOpen(module.mref(), pn)) {
+                try {
+                    url = findResource(module.name(), name);
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        } else {
+            for (ModuleReference mref : nameToModule.values()) {
+                try {
+                    url = findResource(mref.descriptor().name(), name);
+                    if (url != null)
+                        break;
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        }
+        return url;
+    }
+
+    @Override
+    public Enumeration<URL> findResources(String name) throws IOException {
+        List<URL> urls = new ArrayList<>();
+        String pn = ResourceHelper.getPackageName(name);
+        LoadedModule module = localPackageToModule.get(pn);
+        if (module != null) {
+            if (name.endsWith(".class") || isOpen(module.mref(), pn)) {
+                try {
+                    URL url = findResource(module.name(), name);
+                    if (url != null)
+                        urls.add(url);
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        } else {
+            for (ModuleReference mref : nameToModule.values()) {
+                try {
+                    URL url = findResource(mref.descriptor().name(), name);
+                    if (url != null)
+                        urls.add(url);
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        }
+        return Collections.enumeration(urls);
     }
 
 
@@ -544,4 +633,24 @@
         }
     }
 
+    /**
+     * Returns true if the given module opens the given package
+     * unconditionally.
+     *
+     * @implNote This method currently iterates over each of the open
+     * packages. This will be replaced once the ModuleDescriptor.Opens
+     * API is updated.
+     */
+    private boolean isOpen(ModuleReference mref, String pn) {
+        ModuleDescriptor descriptor = mref.descriptor();
+        if (descriptor.isOpen())
+            return true;
+        for (ModuleDescriptor.Opens opens : descriptor.opens()) {
+            String source = opens.source();
+            if (!opens.isQualified() && source.equals(pn)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,10 +26,10 @@
 package jdk.internal.loader;
 
 import java.lang.module.Configuration;
-import java.lang.module.ModuleReference;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.stream.Stream;
 
@@ -51,7 +51,7 @@
      * created with the given parent class loader as its parent.
      */
     public LoaderPool(Configuration cf,
-                      Layer parentLayer,
+                      List<Layer> parentLayers,
                       ClassLoader parentLoader)
     {
         Map<String, Loader> loaders = new HashMap<>();
@@ -63,7 +63,7 @@
         this.loaders = loaders;
 
         // complete the initialization
-        loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayer));
+        loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayers));
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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.loader;
+
+import jdk.internal.module.Checks;
+
+/**
+ * Helper class for Class#getResource, Module#getResourceAsStream, and other
+ * methods that locate a resource in a module.
+ */
+public final class ResourceHelper {
+    private ResourceHelper() { }
+
+    /**
+     * Returns the <em>package name</em> for a resource.
+     */
+    public static String getPackageName(String name) {
+        int index = name.lastIndexOf('/');
+        if (index != -1) {
+            return name.substring(0, index).replace("/", ".");
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Returns true if the resource is a <em>simple resource</em> that can
+     * never be encapsulated. Resources ending in "{@code .class}" or where
+     * the package name is not a Java identifier are resources that can
+     * never be encapsulated.
+     */
+    public static boolean isSimpleResource(String name) {
+        int len = name.length();
+        if (len > 6 && name.endsWith(".class")) {
+            return true;
+        }
+        if (!Checks.isJavaIdentifier(getPackageName(name))) {
+            return true;
+        }
+        return false;
+    }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Executable;
 import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
 import java.lang.reflect.Module;
 import java.net.URL;
 import java.security.AccessControlContext;
@@ -36,12 +37,19 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Stream;
 
-import jdk.internal.module.ServicesCatalog;
 import jdk.internal.reflect.ConstantPool;
 import sun.reflect.annotation.AnnotationType;
 import sun.nio.ch.Interruptible;
 
 public interface JavaLangAccess {
+
+    /**
+     * Returns a {@code Method} object that reflects the specified public
+     * member method of the given class. Returns {@code null} if the
+     * method is not defined.
+     */
+    Method getMethodOrNull(Class<?> klass, String name, Class<?>... parameterTypes);
+
     /** Return the constant pool for a class. */
     ConstantPool getConstantPool(Class<?> klass);
 
@@ -136,17 +144,6 @@
     Layer getBootLayer();
 
     /**
-     * Returns the ServicesCatalog for the given class loader.
-     */
-    ServicesCatalog getServicesCatalog(ClassLoader cl);
-
-    /**
-     * Returns the ServicesCatalog for the given class loader, creating it
-     * if doesn't already exist.
-     */
-    ServicesCatalog createOrGetServicesCatalog(ClassLoader cl);
-
-    /**
      * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s)
      * associated with the given class loader, creating it if it doesn't already exist.
      */
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,24 +27,26 @@
 
 import java.io.PrintStream;
 import java.lang.module.Configuration;
-import jdk.internal.module.ModuleHashes;
-
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Version;
 import java.lang.module.ModuleFinder;
-import java.util.Collection;
 import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.net.URI;
 import java.nio.file.Path;
 import java.util.Map;
+import java.util.Collection;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Supplier;
 
+import jdk.internal.module.ModuleHashes;
+
 /**
  * Provides access to non-public methods in java.lang.module.
  */
@@ -52,28 +54,59 @@
 public interface JavaLangModuleAccess {
 
     /**
-     * Returns {@code ModuleDescriptor.Requires} of the given modifier
+     * Creates a builder for building a module with the given module name.
+     *
+     * @param strict
+     *        Indicates whether module names are checked or not
+     */
+    ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict);
+
+    /**
+     * Creates a builder for building an open module with the given module name.
+     *
+     * @param strict
+     *        Indicates whether module names are checked or not
+     */
+    ModuleDescriptor.Builder newOpenModuleBuilder(String mn, boolean strict);
+
+    /**
+     * Returns a {@code ModuleDescriptor.Requires} of the given modifiers
      * and module name.
      */
     Requires newRequires(Set<Requires.Modifier> ms, String mn);
 
     /**
      * Returns an unqualified {@code ModuleDescriptor.Exports}
-     * of the given package name.
+     * of the given modifiers and package name source.
      */
-    Exports newExports(String source);
+    Exports newExports(Set<Exports.Modifier> ms,
+                       String source);
 
     /**
      * Returns a qualified {@code ModuleDescriptor.Exports}
-     * of the given package name and targets.
+     * of the given modifiers, package name source and targets.
      */
-    Exports newExports(String source, Set<String> targets);
+    Exports newExports(Set<Exports.Modifier> ms,
+                       String source,
+                       Set<String> targets);
+
+    /**
+     * Returns an unqualified {@code ModuleDescriptor.Opens}
+     * of the given modifiers and package name source.
+     */
+    Opens newOpens(Set<Opens.Modifier> ms, String source);
+
+    /**
+     * Returns a qualified {@code ModuleDescriptor.Opens}
+     * of the given modifiers, package name source and targets.
+     */
+    Opens newOpens(Set<Opens.Modifier> ms, String source, Set<String> targets);
 
     /**
      * Returns a {@code ModuleDescriptor.Provides}
      * of the given service name and providers.
      */
-    Provides newProvides(String service, Set<String> providers);
+    Provides newProvides(String service, List<String> providers);
 
     /**
      * Returns a {@code ModuleDescriptor.Version} of the given version.
@@ -89,19 +122,22 @@
      * Returns a new {@code ModuleDescriptor} instance.
      */
     ModuleDescriptor newModuleDescriptor(String name,
+                                         boolean open,
                                          boolean automatic,
                                          boolean synthetic,
                                          Set<Requires> requires,
+                                         Set<Exports> exports,
+                                         Set<Opens> opens,
                                          Set<String> uses,
-                                         Set<Exports> exports,
-                                         Map<String, Provides> provides,
+                                         Set<Provides> provides,
                                          Version version,
                                          String mainClass,
                                          String osName,
                                          String osArch,
                                          String osVersion,
                                          Set<String> packages,
-                                         ModuleHashes hashes);
+                                         ModuleHashes hashes,
+                                         int hashCode);
 
     /**
      * Returns the object with the hashes of other modules
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.net.URI;
+import java.util.stream.Stream;
 
 import jdk.internal.module.ServicesCatalog;
 
@@ -71,16 +72,37 @@
     void addExports(Module m1, String pkg, Module m2);
 
     /**
+     * Updates module m1 to open a package to module m2. Opening the
+     * package does not result in a strong reference to m2 (m2 can be GC'ed).
+     */
+    void addOpens(Module m1, String pkg, Module m2);
+
+    /**
      * Updates a module m to export a package to all modules.
      */
     void addExportsToAll(Module m, String pkg);
 
     /**
+     * Updates a module m to open a package to all modules.
+     */
+    void addOpensToAll(Module m, String pkg);
+
+    /**
      * Updates a module m to export a package to all unnamed modules.
      */
     void addExportsToAllUnnamed(Module m, String pkg);
 
     /**
+     * Updates a module m to open a package to all unnamed modules.
+     */
+    void addOpensToAllUnnamed(Module m, String pkg);
+
+    /**
+     * Updates a module m to use a service.
+     */
+    void addUses(Module m, Class<?> service);
+
+    /**
      * Add a package to the given module.
      */
     void addPackage(Module m, String pkg);
@@ -90,4 +112,15 @@
      */
     ServicesCatalog getServicesCatalog(Layer layer);
 
+    /**
+     * Returns an ordered stream of layers. The first element is is the
+     * given layer, the remaining elements are its parents, in DFS order.
+     */
+    Stream<Layer> layers(Layer layer);
+
+    /**
+     * Returns a stream of the layers that have modules defined to the
+     * given class loader.
+     */
+    Stream<Layer> layers(ClassLoader loader);
 }
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
 
 package jdk.internal.misc;
 
+import java.lang.reflect.Module;
 import java.util.Locale;
 import java.util.ResourceBundle;
 
@@ -51,4 +52,16 @@
      * Sets the bundle's base name to the given name.
      */
     void setName(ResourceBundle bundle, String name);
+
+    /**
+     * Returns a {@code ResourceBundle} of the given baseName and locale
+     * loaded on behalf of the given module with no caller module
+     * access check.
+     */
+    ResourceBundle getBundle(String baseName, Locale locale, Module module);
+
+    /**
+     * Instantiates a {@code ResourceBundle} of the given bundle class.
+     */
+    ResourceBundle newResourceBundle(Class<? extends ResourceBundle> bundleClass);
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
 package jdk.internal.misc;
 
 import java.lang.module.ModuleDescriptor;
+import java.util.ResourceBundle;
 import java.util.jar.JarFile;
 import java.io.Console;
 import java.io.FileDescriptor;
@@ -294,6 +295,8 @@
     }
 
     public static JavaUtilResourceBundleAccess getJavaUtilResourceBundleAccess() {
+        if (javaUtilResourceBundleAccess == null)
+            unsafe.ensureClassInitialized(ResourceBundle.class);
         return javaUtilResourceBundleAccess;
     }
 
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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,12 +26,14 @@
 
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Version;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -40,7 +42,7 @@
 
 /**
  * This builder is optimized for reconstituting ModuleDescriptor
- * for installed modules.  The validation should be done at jlink time.
+ * for system modules.  The validation should be done at jlink time.
  *
  * 1. skip name validation
  * 2. ignores dependency hashes.
@@ -53,66 +55,137 @@
     private static final JavaLangModuleAccess jlma =
         SharedSecrets.getJavaLangModuleAccess();
 
-    private static final Set<Requires.Modifier> MANDATED =
-        Collections.singleton(Requires.Modifier.MANDATED);
-    private static final Set<Requires.Modifier> PUBLIC =
-        Collections.singleton(Requires.Modifier.PUBLIC);
-
     // Static cache of the most recently seen Version to cheaply deduplicate
     // most Version objects.  JDK modules have the same version.
     static Version cachedVersion;
 
+    /**
+     * Returns a {@link Requires} for a dependence on a module
+     * with the given (and possibly empty) set of modifiers.
+     */
+    public static Requires newRequires(Set<Requires.Modifier> mods,
+                                       String mn)
+    {
+        return jlma.newRequires(mods, mn);
+    }
+
+    /**
+     * Returns a {@link Exports} for a qualified export, with
+     * the given (and possibly empty) set of modifiers,
+     * to a set of target modules.
+     */
+    public static Exports newExports(Set<Exports.Modifier> ms,
+                                     String pn,
+                                     Set<String> targets) {
+        return jlma.newExports(ms, pn, targets);
+    }
+
+    /**
+     * Returns an {@link Opens} for an unqualified open with a given set of
+     * modifiers.
+     */
+    public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
+        return jlma.newOpens(ms, pn);
+    }
+
+    /**
+     * Returns an {@link Opens} for a qualified opens, with
+     * the given (and possibly empty) set of modifiers,
+     * to a set of target modules.
+     */
+    public static Opens newOpens(Set<Opens.Modifier> ms,
+                                 String pn,
+                                 Set<String> targets) {
+        return jlma.newOpens(ms, pn, targets);
+    }
+
+    /**
+     * Returns a {@link Exports} for an unqualified export with a given set
+     * of modifiers.
+     */
+    public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
+        return jlma.newExports(ms, pn);
+    }
+
+    /**
+     * Returns a {@link Provides} for a service with a given list of
+     * implementation classes.
+     */
+    public static Provides newProvides(String st, List<String> pcs) {
+        return jlma.newProvides(st, pcs);
+    }
+
     final String name;
-    final Set<Requires> requires;
-    final Set<Exports> exports;
-    final Map<String, Provides> provides;
+    boolean open;
+    boolean automatic;
+    boolean synthetic;
+    Set<Requires> requires;
+    Set<Exports> exports;
+    Set<Opens> opens;
     Set<String> packages;
     Set<String> uses;
+    Set<Provides> provides;
     Version version;
     String mainClass;
     String osName;
     String osArch;
     String osVersion;
     String algorithm;
-    Map<String, String> hashes;
+    Map<String, byte[]> hashes;
 
-    Builder(String name, int reqs, int exports,
-            int provides, int packages) {
+    Builder(String name) {
         this.name = name;
-        this.requires = reqs > 0 ? new HashSet<>(reqs) : Collections.emptySet();
-        this.exports  = exports > 0 ? new HashSet<>(exports) : Collections.emptySet();
-        this.provides = provides > 0 ? new HashMap<>(provides) : Collections.emptyMap();
+        this.requires = Collections.emptySet();
+        this.exports = Collections.emptySet();
+        this.opens = Collections.emptySet();
+        this.provides = Collections.emptySet();
         this.uses = Collections.emptySet();
     }
 
-    /**
-     * Adds a module dependence with the given (and possibly empty) set
-     * of modifiers.
-     */
-    public Builder requires(Set<Requires.Modifier> mods, String mn) {
-        requires.add(jlma.newRequires(Collections.unmodifiableSet(mods), mn));
+    Builder open(boolean value) {
+        this.open = value;
+        return this;
+    }
+
+    Builder automatic(boolean value) {
+        this.automatic = value;
+        return this;
+    }
+
+    Builder synthetic(boolean value) {
+        this.synthetic = value;
         return this;
     }
 
     /**
-     * Adds a module dependence with an empty set of modifiers.
+     * Sets module exports.
      */
-    public Builder requires(String mn) {
-        requires.add(jlma.newRequires(Collections.emptySet(), mn));
+    public Builder exports(Exports[] exports) {
+        this.exports = Set.of(exports);
         return this;
     }
 
     /**
-     * Adds a module dependence with the given modifier.
+     * Sets module opens.
+     */
+    public Builder opens(Opens[] opens) {
+        this.opens = Set.of(opens);
+        return this;
+    }
+
+    /**
+     * Sets module requires.
      */
-    public Builder requires(Requires.Modifier mod, String mn) {
-        if (mod == Requires.Modifier.MANDATED) {
-            requires.add(jlma.newRequires(MANDATED, mn));
-        } else if (mod == Requires.Modifier.PUBLIC) {
-            requires.add(jlma.newRequires(PUBLIC, mn));
-        } else {
-            requires.add(jlma.newRequires(Collections.singleton(mod), mn));
-        }
+    public Builder requires(Requires[] requires) {
+        this.requires = Set.of(requires);
+        return this;
+    }
+
+    /**
+     * Adds a set of (possible empty) packages.
+     */
+    public Builder packages(Set<String> packages) {
+        this.packages = packages;
         return this;
     }
 
@@ -125,51 +198,10 @@
     }
 
     /**
-     * Adds an export to a set of target modules.
-     */
-    public Builder exports(String pn, Set<String> targets) {
-        exports.add(jlma.newExports(pn, targets));
-        return this;
-    }
-
-    /**
-     * Adds an export to a target module.
-     */
-    public Builder exports(String pn, String target) {
-        return exports(pn, Collections.singleton(target));
-    }
-
-    /**
-     * Adds an export.
+     * Sets module provides.
      */
-    public Builder exports(String pn) {
-        exports.add(jlma.newExports(pn));
-        return this;
-    }
-
-    /**
-     * Provides service {@code st} with implementations {@code pcs}.
-     */
-    public Builder provides(String st, Set<String> pcs) {
-        if (provides.containsKey(st))
-            throw new IllegalStateException("Providers of service "
-                    + st + " already declared");
-        provides.put(st, jlma.newProvides(st, pcs));
-        return this;
-    }
-
-    /**
-     * Provides service {@code st} with implementation {@code pc}.
-     */
-    public Builder provides(String st, String pc) {
-        return provides(st, Collections.singleton(pc));
-    }
-
-    /**
-     * Adds a set of (possible empty) packages.
-     */
-    public Builder packages(Set<String> packages) {
-        this.packages = packages;
+    public Builder provides(Provides[] provides) {
+        this.provides = Set.of(provides);
         return this;
     }
 
@@ -253,7 +285,7 @@
     /**
      * Sets the module hash for the given module name
      */
-    public Builder moduleHash(String mn, String hash) {
+    public Builder moduleHash(String mn, byte[] hash) {
         if (hashes == null)
             hashes = new HashMap<>();
 
@@ -264,18 +296,20 @@
     /**
      * Builds a {@code ModuleDescriptor} from the components.
      */
-    public ModuleDescriptor build() {
+    public ModuleDescriptor build(int hashCode) {
         assert name != null;
 
         ModuleHashes moduleHashes =
             hashes != null ? new ModuleHashes(algorithm, hashes) : null;
 
         return jlma.newModuleDescriptor(name,
-                                        false,    // automatic
-                                        false,    // assume not synthetic for now
+                                        open,
+                                        automatic,
+                                        synthetic,
                                         requires,
+                                        exports,
+                                        opens,
                                         uses,
-                                        exports,
                                         provides,
                                         version,
                                         mainClass,
@@ -283,6 +317,7 @@
                                         osArch,
                                         osVersion,
                                         packages,
-                                        moduleHashes);
+                                        moduleHashes,
+                                        hashCode);
     }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,6 @@
 
 package jdk.internal.module;
 
-
 public final class Checks {
 
     private Checks() { }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -27,17 +27,20 @@
 
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Version;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.org.objectweb.asm.Attribute;
 import jdk.internal.org.objectweb.asm.ByteVector;
 import jdk.internal.org.objectweb.asm.ClassReader;
@@ -51,7 +54,7 @@
  * class file attributes in a module-info class file.
  */
 
-class ClassFileAttributes {
+public final class ClassFileAttributes {
 
     private ClassFileAttributes() { }
 
@@ -60,16 +63,18 @@
      *   // See lang-vm.html for details.
      * }
      */
-    static class ModuleAttribute extends Attribute {
+    public static class ModuleAttribute extends Attribute {
+        private static final JavaLangModuleAccess JLMA
+            = SharedSecrets.getJavaLangModuleAccess();
 
         private ModuleDescriptor descriptor;
 
-        ModuleAttribute(ModuleDescriptor descriptor) {
+        public ModuleAttribute(ModuleDescriptor descriptor) {
             super(MODULE);
             this.descriptor = descriptor;
         }
 
-        ModuleAttribute() {
+        public ModuleAttribute() {
             super(MODULE);
         }
 
@@ -81,27 +86,43 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            ModuleDescriptor.Builder builder
-                = new ModuleDescriptor.Builder("xyzzy"); // Name never used
             ModuleAttribute attr = new ModuleAttribute();
 
+            // module_name
+            String mn = cr.readUTF8(off, buf).replace('/', '.');
+            off += 2;
+
+            // module_flags
+            int module_flags = cr.readUnsignedShort(off);
+            boolean open = ((module_flags & ACC_OPEN) != 0);
+            off += 2;
+
+            ModuleDescriptor.Builder builder;
+            if (open) {
+                builder = JLMA.newOpenModuleBuilder(mn, false);
+            } else {
+                builder = JLMA.newModuleBuilder(mn, false);
+            }
+
             // requires_count and requires[requires_count]
             int requires_count = cr.readUnsignedShort(off);
             off += 2;
             for (int i=0; i<requires_count; i++) {
-                String dn = cr.readUTF8(off, buf);
+                String dn = cr.readUTF8(off, buf).replace('/', '.');
                 int flags = cr.readUnsignedShort(off + 2);
-                Set<Modifier> mods;
+                Set<Requires.Modifier> mods;
                 if (flags == 0) {
                     mods = Collections.emptySet();
                 } else {
                     mods = new HashSet<>();
-                    if ((flags & ACC_PUBLIC) != 0)
-                        mods.add(Modifier.PUBLIC);
+                    if ((flags & ACC_TRANSITIVE) != 0)
+                        mods.add(Requires.Modifier.TRANSITIVE);
+                    if ((flags & ACC_STATIC_PHASE) != 0)
+                        mods.add(Requires.Modifier.STATIC);
                     if ((flags & ACC_SYNTHETIC) != 0)
-                        mods.add(Modifier.SYNTHETIC);
+                        mods.add(Requires.Modifier.SYNTHETIC);
                     if ((flags & ACC_MANDATED) != 0)
-                        mods.add(Modifier.MANDATED);
+                        mods.add(Requires.Modifier.MANDATED);
                 }
                 builder.requires(mods, dn);
                 off += 4;
@@ -113,18 +134,70 @@
             if (exports_count > 0) {
                 for (int i=0; i<exports_count; i++) {
                     String pkg = cr.readUTF8(off, buf).replace('/', '.');
-                    int exports_to_count = cr.readUnsignedShort(off+2);
-                    off += 4;
+                    off += 2;
+
+                    int flags = cr.readUnsignedShort(off);
+                    off += 2;
+                    Set<Exports.Modifier> mods;
+                    if (flags == 0) {
+                        mods = Collections.emptySet();
+                    } else {
+                        mods = new HashSet<>();
+                        if ((flags & ACC_SYNTHETIC) != 0)
+                            mods.add(Exports.Modifier.SYNTHETIC);
+                        if ((flags & ACC_MANDATED) != 0)
+                            mods.add(Exports.Modifier.MANDATED);
+                    }
+
+                    int exports_to_count = cr.readUnsignedShort(off);
+                    off += 2;
                     if (exports_to_count > 0) {
                         Set<String> targets = new HashSet<>();
                         for (int j=0; j<exports_to_count; j++) {
-                            String t = cr.readUTF8(off, buf);
+                            String t = cr.readUTF8(off, buf).replace('/', '.');
                             off += 2;
                             targets.add(t);
                         }
-                        builder.exports(pkg, targets);
+                        builder.exports(mods, pkg, targets);
                     } else {
-                        builder.exports(pkg);
+                        builder.exports(mods, pkg);
+                    }
+                }
+            }
+
+            // opens_count and opens[opens_count]
+            int open_count = cr.readUnsignedShort(off);
+            off += 2;
+            if (open_count > 0) {
+                for (int i=0; i<open_count; i++) {
+                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    off += 2;
+
+                    int flags = cr.readUnsignedShort(off);
+                    off += 2;
+                    Set<Opens.Modifier> mods;
+                    if (flags == 0) {
+                        mods = Collections.emptySet();
+                    } else {
+                        mods = new HashSet<>();
+                        if ((flags & ACC_SYNTHETIC) != 0)
+                            mods.add(Opens.Modifier.SYNTHETIC);
+                        if ((flags & ACC_MANDATED) != 0)
+                            mods.add(Opens.Modifier.MANDATED);
+                    }
+
+                    int opens_to_count = cr.readUnsignedShort(off);
+                    off += 2;
+                    if (opens_to_count > 0) {
+                        Set<String> targets = new HashSet<>();
+                        for (int j=0; j<opens_to_count; j++) {
+                            String t = cr.readUTF8(off, buf).replace('/', '.');
+                            off += 2;
+                            targets.add(t);
+                        }
+                        builder.opens(mods, pkg, targets);
+                    } else {
+                        builder.opens(mods, pkg);
                     }
                 }
             }
@@ -144,15 +217,19 @@
             int provides_count = cr.readUnsignedShort(off);
             off += 2;
             if (provides_count > 0) {
-                Map<String, Set<String>> provides = new HashMap<>();
                 for (int i=0; i<provides_count; i++) {
-                    String sn = cr.readClass(off, buf).replace('/', '.');
-                    String cn = cr.readClass(off + 2, buf).replace('/', '.');
-                    provides.computeIfAbsent(sn, k -> new LinkedHashSet<>()).add(cn);
-                    off += 4;
+                    String service = cr.readClass(off, buf).replace('/', '.');
+                    off += 2;
+                    int with_count = cr.readUnsignedShort(off);
+                    off += 2;
+                    List<String> providers = new ArrayList<>();
+                    for (int j=0; j<with_count; j++) {
+                        String cn = cr.readClass(off, buf).replace('/', '.');
+                        off += 2;
+                        providers.add(cn);
+                    }
+                    builder.provides(service, providers);
                 }
-                provides.entrySet().forEach(e -> builder.provides(e.getKey(),
-                                                                  e.getValue()));
             }
 
             attr.descriptor = builder.build();
@@ -169,6 +246,19 @@
             assert descriptor != null;
             ByteVector attr = new ByteVector();
 
+            // module_name
+            String mn = descriptor.name();
+            int module_name_index = cw.newUTF8(mn.replace('.', '/'));
+            attr.putShort(module_name_index);
+
+            // module_flags
+            int module_flags = 0;
+            if (descriptor.isOpen())
+                module_flags |= ACC_OPEN;
+            if (descriptor.isSynthetic())
+                module_flags |= ACC_SYNTHETIC;
+            attr.putShort(module_flags);
+
             // requires_count
             attr.putShort(descriptor.requires().size());
 
@@ -176,32 +266,61 @@
             for (Requires md : descriptor.requires()) {
                 String dn = md.name();
                 int flags = 0;
-                if (md.modifiers().contains(Modifier.PUBLIC))
-                    flags |= ACC_PUBLIC;
-                if (md.modifiers().contains(Modifier.SYNTHETIC))
+                if (md.modifiers().contains(Requires.Modifier.TRANSITIVE))
+                    flags |= ACC_TRANSITIVE;
+                if (md.modifiers().contains(Requires.Modifier.STATIC))
+                    flags |= ACC_STATIC_PHASE;
+                if (md.modifiers().contains(Requires.Modifier.SYNTHETIC))
                     flags |= ACC_SYNTHETIC;
-                if (md.modifiers().contains(Modifier.MANDATED))
+                if (md.modifiers().contains(Requires.Modifier.MANDATED))
                     flags |= ACC_MANDATED;
-                int index = cw.newUTF8(dn);
+                int index = cw.newUTF8(dn.replace('.', '/'));
                 attr.putShort(index);
                 attr.putShort(flags);
             }
 
             // exports_count and exports[exports_count];
-            if (descriptor.exports().isEmpty()) {
-                attr.putShort(0);
-            } else {
-                attr.putShort(descriptor.exports().size());
-                for (Exports e : descriptor.exports()) {
-                    String pkg = e.source().replace('.', '/');
-                    attr.putShort(cw.newUTF8(pkg));
-                    if (e.isQualified()) {
-                        Set<String> ts = e.targets();
-                        attr.putShort(ts.size());
-                        ts.forEach(t -> attr.putShort(cw.newUTF8(t)));
-                    } else {
-                        attr.putShort(0);
-                    }
+            attr.putShort(descriptor.exports().size());
+            for (Exports e : descriptor.exports()) {
+                String pkg = e.source().replace('.', '/');
+                attr.putShort(cw.newUTF8(pkg));
+
+                int flags = 0;
+                if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
+                    flags |= ACC_SYNTHETIC;
+                if (e.modifiers().contains(Exports.Modifier.MANDATED))
+                    flags |= ACC_MANDATED;
+                attr.putShort(flags);
+
+                if (e.isQualified()) {
+                    Set<String> ts = e.targets();
+                    attr.putShort(ts.size());
+                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                } else {
+                    attr.putShort(0);
+                }
+            }
+
+
+            // opens_counts and opens[opens_counts]
+            attr.putShort(descriptor.opens().size());
+            for (Opens obj : descriptor.opens()) {
+                String pkg = obj.source().replace('.', '/');
+                attr.putShort(cw.newUTF8(pkg));
+
+                int flags = 0;
+                if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
+                    flags |= ACC_SYNTHETIC;
+                if (obj.modifiers().contains(Opens.Modifier.MANDATED))
+                    flags |= ACC_MANDATED;
+                attr.putShort(flags);
+
+                if (obj.isQualified()) {
+                    Set<String> ts = obj.targets();
+                    attr.putShort(ts.size());
+                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                } else {
+                    attr.putShort(0);
                 }
             }
 
@@ -221,14 +340,13 @@
             if (descriptor.provides().isEmpty()) {
                 attr.putShort(0);
             } else {
-                int count = descriptor.provides().values()
-                    .stream().mapToInt(ps -> ps.providers().size()).sum();
-                attr.putShort(count);
-                for (Provides p : descriptor.provides().values()) {
+                attr.putShort(descriptor.provides().size());
+                for (Provides p : descriptor.provides()) {
                     String service = p.service().replace('.', '/');
-                    int index = cw.newClass(service);
+                    attr.putShort(cw.newClass(service));
+                    int with_count = p.providers().size();
+                    attr.putShort(with_count);
                     for (String provider : p.providers()) {
-                        attr.putShort(index);
                         attr.putShort(cw.newClass(provider.replace('.', '/')));
                     }
                 }
@@ -239,44 +357,13 @@
     }
 
     /**
-     * Synthetic attribute.
-     */
-    static class SyntheticAttribute extends Attribute {
-        SyntheticAttribute() {
-            super(SYNTHETIC);
-        }
-
-        @Override
-        protected Attribute read(ClassReader cr,
-                                 int off,
-                                 int len,
-                                 char[] buf,
-                                 int codeOff,
-                                 Label[] labels)
-        {
-            return new SyntheticAttribute();
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            ByteVector attr = new ByteVector();
-            return attr;
-        }
-    }
-
-    /**
-     * ConcealedPackages attribute.
+     * ModulePackages attribute.
      *
      * <pre> {@code
      *
-     * ConcealedPackages_attribute {
+     * ModulePackages_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ConcealedPackages"
+     *   // the string "ModulePackages"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -288,15 +375,15 @@
      *
      * }</pre>
      */
-    static class ConcealedPackagesAttribute extends Attribute {
+    public static class ModulePackagesAttribute extends Attribute {
         private final Set<String> packages;
 
-        ConcealedPackagesAttribute(Set<String> packages) {
-            super(CONCEALED_PACKAGES);
+        public ModulePackagesAttribute(Set<String> packages) {
+            super(MODULE_PACKAGES);
             this.packages = packages;
         }
 
-        ConcealedPackagesAttribute() {
+        public ModulePackagesAttribute() {
             this(null);
         }
 
@@ -320,7 +407,7 @@
                 off += 2;
             }
 
-            return new ConcealedPackagesAttribute(packages);
+            return new ModulePackagesAttribute(packages);
         }
 
         @Override
@@ -348,13 +435,13 @@
     }
 
     /**
-     * Version attribute.
+     * ModuleVersion attribute.
      *
      * <pre> {@code
      *
-     * Version_attribute {
+     * ModuleVersion_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "Version"
+     *   // the string "ModuleVersion"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -364,15 +451,15 @@
      *
      * } </pre>
      */
-    static class VersionAttribute extends Attribute {
+    public static class ModuleVersionAttribute extends Attribute {
         private final Version version;
 
-        VersionAttribute(Version version) {
-            super(VERSION);
+        public ModuleVersionAttribute(Version version) {
+            super(MODULE_VERSION);
             this.version = version;
         }
 
-        VersionAttribute() {
+        public ModuleVersionAttribute() {
             this(null);
         }
 
@@ -385,7 +472,7 @@
                                  Label[] labels)
         {
             String value = cr.readUTF8(off, buf);
-            return new VersionAttribute(Version.parse(value));
+            return new ModuleVersionAttribute(Version.parse(value));
         }
 
         @Override
@@ -403,13 +490,13 @@
     }
 
     /**
-     * MainClass attribute.
+     * ModuleMainClass attribute.
      *
      * <pre> {@code
      *
      * MainClass_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "MainClass"
+     *   // the string "ModuleMainClass"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -419,15 +506,15 @@
      *
      * } </pre>
      */
-    static class MainClassAttribute extends Attribute {
+    public static class ModuleMainClassAttribute extends Attribute {
         private final String mainClass;
 
-        MainClassAttribute(String mainClass) {
-            super(MAIN_CLASS);
+        public ModuleMainClassAttribute(String mainClass) {
+            super(MODULE_MAIN_CLASS);
             this.mainClass = mainClass;
         }
 
-        MainClassAttribute() {
+        public ModuleMainClassAttribute() {
             this(null);
         }
 
@@ -440,7 +527,7 @@
                                  Label[] labels)
         {
             String value = cr.readClass(off, buf);
-            return new MainClassAttribute(value);
+            return new ModuleMainClassAttribute(value);
         }
 
         @Override
@@ -458,13 +545,13 @@
     }
 
     /**
-     * TargetPlatform attribute.
+     * ModuleTarget attribute.
      *
      * <pre> {@code
      *
      * TargetPlatform_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "TargetPlatform"
+     *   // the string "ModuleTarget"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -478,19 +565,19 @@
      *
      * } </pre>
      */
-    static class TargetPlatformAttribute extends Attribute {
+    public static class ModuleTargetAttribute extends Attribute {
         private final String osName;
         private final String osArch;
         private final String osVersion;
 
-        TargetPlatformAttribute(String osName, String osArch, String osVersion) {
-            super(TARGET_PLATFORM);
+        public ModuleTargetAttribute(String osName, String osArch, String osVersion) {
+            super(MODULE_TARGET);
             this.osName = osName;
             this.osArch = osArch;
             this.osVersion = osVersion;
         }
 
-        TargetPlatformAttribute() {
+        public ModuleTargetAttribute() {
             this(null, null, null);
         }
 
@@ -522,7 +609,7 @@
                 osVersion = cr.readUTF8(off, buf);
             off += 2;
 
-            return new TargetPlatformAttribute(osName, osArch, osVersion);
+            return new ModuleTargetAttribute(osName, osArch, osVersion);
         }
 
         @Override
@@ -554,39 +641,37 @@
     }
 
     /**
-     * Hashes attribute.
+     * ModuleHashes attribute.
      *
      * <pre> {@code
      *
-     * Hashes_attribute {
+     * ModuleHashes_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "Hashes"
+     *   // the string "ModuleHashes"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with algorithm name
+     *   // index to CONSTANT_utf8_info structure with algorithm name
      *   u2 algorithm_index;
      *
      *   // the number of entries in the hashes table
-     *   u2 hash_count;
-     *   {   u2 requires_index
-     *       u2 hash_index;
-     *   } hashes[hash_count];
+     *   u2 hashes_count;
+     *   {   u2 module_name_index
+     *       u2 hash_length;
+     *       u1 hash[hash_length];
+     *   } hashes[hashes_count];
      *
      * } </pre>
-     *
-     * @apiNote For now the hash is stored in base64 as a UTF-8 string, an
-     * alternative is to store it as an array of u1.
      */
-    static class HashesAttribute extends Attribute {
+    static class ModuleHashesAttribute extends Attribute {
         private final ModuleHashes hashes;
 
-        HashesAttribute(ModuleHashes hashes) {
-            super(HASHES);
+        ModuleHashesAttribute(ModuleHashes hashes) {
+            super(MODULE_HASHES);
             this.hashes = hashes;
         }
 
-        HashesAttribute() {
+        ModuleHashesAttribute() {
             this(null);
         }
 
@@ -601,21 +686,28 @@
             String algorithm = cr.readUTF8(off, buf);
             off += 2;
 
-            int hash_count = cr.readUnsignedShort(off);
+            int hashes_count = cr.readUnsignedShort(off);
             off += 2;
 
-            Map<String, String> map = new HashMap<>();
-            for (int i=0; i<hash_count; i++) {
-                String dn = cr.readUTF8(off, buf);
+            Map<String, byte[]> map = new HashMap<>();
+            for (int i=0; i<hashes_count; i++) {
+                String mn = cr.readUTF8(off, buf).replace('/', '.');
+                off += 2;
+
+                int hash_length = cr.readUnsignedShort(off);
                 off += 2;
-                String hash = cr.readUTF8(off, buf);
-                off += 2;
-                map.put(dn, hash);
+                byte[] hash = new byte[hash_length];
+                for (int j=0; j<hash_length; j++) {
+                    hash[j] = (byte) (0xff & cr.readByte(off+j));
+                }
+                off += hash_length;
+
+                map.put(mn, hash);
             }
 
             ModuleHashes hashes = new ModuleHashes(algorithm, map);
 
-            return new HashesAttribute(hashes);
+            return new ModuleHashesAttribute(hashes);
         }
 
         @Override
@@ -633,11 +725,15 @@
             Set<String> names = hashes.names();
             attr.putShort(names.size());
 
-            for (String dn : names) {
-                String hash = hashes.hashFor(dn);
+            for (String mn : names) {
+                byte[] hash = hashes.hashFor(mn);
                 assert hash != null;
-                attr.putShort(cw.newUTF8(dn));
-                attr.putShort(cw.newUTF8(hash));
+                attr.putShort(cw.newUTF8(mn.replace('.', '/')));
+
+                attr.putShort(hash.length);
+                for (byte b: hash) {
+                    attr.putByte(b);
+                }
             }
 
             return attr;
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Wed Jul 05 22:32:06 2017 +0200
@@ -35,19 +35,20 @@
     // Attribute names
     public static final String MODULE             = "Module";
     public static final String SOURCE_FILE        = "SourceFile";
-    public static final String SYNTHETIC          = "Synthetic";
     public static final String SDE                = "SourceDebugExtension";
 
-    public static final String CONCEALED_PACKAGES = "ConcealedPackages";
-    public static final String VERSION            = "Version";
-    public static final String MAIN_CLASS         = "MainClass";
-    public static final String TARGET_PLATFORM    = "TargetPlatform";
-    public static final String HASHES             = "Hashes";
+    public static final String MODULE_PACKAGES    = "ModulePackages";
+    public static final String MODULE_VERSION     = "ModuleVersion";
+    public static final String MODULE_MAIN_CLASS  = "ModuleMainClass";
+    public static final String MODULE_TARGET      = "ModuleTarget";
+    public static final String MODULE_HASHES      = "ModuleHashes";
 
-    // access and requires flags
-    public static final int ACC_MODULE       = 0x8000;
-    public static final int ACC_PUBLIC       = 0x0020;
-    public static final int ACC_SYNTHETIC    = 0x1000;
-    public static final int ACC_MANDATED     = 0x8000;
+    // access, requires, exports, and opens flags
+    public static final int ACC_MODULE        = 0x8000;
+    public static final int ACC_OPEN          = 0x0020;
+    public static final int ACC_TRANSITIVE    = 0x0010;
+    public static final int ACC_STATIC_PHASE  = 0x0020;
+    public static final int ACC_SYNTHETIC     = 0x1000;
+    public static final int ACC_MANDATED      = 0x8000;
 
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Wed Jul 05 22:32:06 2017 +0200
@@ -37,9 +37,11 @@
 import java.net.URI;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -81,10 +83,20 @@
     // the token for "all modules on the module path"
     private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
 
+    // The ModulePatcher for the initial configuration
+    private static final ModulePatcher patcher = initModulePatcher();
+
     // ModuleFinder for the initial configuration
     private static ModuleFinder initialFinder;
 
     /**
+     * Returns the ModulePatcher for the initial configuration.
+     */
+    public static ModulePatcher patcher() {
+        return patcher;
+    }
+
+    /**
      * Returns the ModuleFinder for the initial configuration
      */
     public static ModuleFinder finder() {
@@ -101,7 +113,7 @@
 
         long t0 = System.nanoTime();
 
-        // system modules
+        // system modules (may be patched)
         ModuleFinder systemModules = ModuleFinder.ofSystem();
 
         PerfCounters.systemModulesTime.addElapsedTimeFrom(t0);
@@ -247,7 +259,7 @@
         if (baseUri.getScheme().equals("jrt")   // toLowerCase not needed here
                 && (upgradeModulePath == null)
                 && (appModulePath == null)
-                && (!ModulePatcher.isBootLayerPatched())) {
+                && (patcher.isEmpty())) {
             needPostResolutionChecks = false;
         }
 
@@ -314,9 +326,9 @@
         PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
 
 
-        // --add-reads and --add-exports
+        // --add-reads, -add-exports/-add-opens
         addExtraReads(bootLayer);
-        addExtraExports(bootLayer);
+        addExtraExportsAndOpens(bootLayer);
 
         // total time to initialize
         PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
@@ -389,6 +401,18 @@
         }
     }
 
+
+    /**
+     * Initialize the module patcher for the initial configuration passed on the
+     * value of the --patch-module options.
+     */
+    private static ModulePatcher initModulePatcher() {
+        Map<String, List<String>> map = decode("jdk.module.patch.",
+                                               File.pathSeparator,
+                                               false);
+        return new ModulePatcher(map);
+    }
+
     /**
      * Returns the set of module names specified via --add-modules options
      * on the command line
@@ -408,7 +432,6 @@
             for (String s : value.split(",")) {
                 if (s.length() > 0) modules.add(s);
             }
-
             index++;
             value = getAndRemoveProperty(prefix + index);
         }
@@ -423,9 +446,11 @@
     private static void addExtraReads(Layer bootLayer) {
 
         // decode the command line options
-        Map<String, Set<String>> map = decode("jdk.module.addreads.");
+        Map<String, List<String>> map = decode("jdk.module.addreads.");
+        if (map.isEmpty())
+            return;
 
-        for (Map.Entry<String, Set<String>> e : map.entrySet()) {
+        for (Map.Entry<String, List<String>> e : map.entrySet()) {
 
             // the key is $MODULE
             String mn = e.getKey();
@@ -448,22 +473,36 @@
                         warn("Unknown module: " + name);
                     }
                 }
-
             }
         }
     }
 
-
     /**
-     * Process the --add-exports options to add any additional read edges that
-     * are specified on the command-line.
+     * Process the --add-exports and --add-opens options to export/open
+     * additional packages specified on the command-line.
      */
-    private static void addExtraExports(Layer bootLayer) {
+    private static void addExtraExportsAndOpens(Layer bootLayer) {
+
+        // --add-exports
+        String prefix = "jdk.module.addexports.";
+        Map<String, List<String>> extraExports = decode(prefix);
+        if (!extraExports.isEmpty()) {
+            addExtraExportsOrOpens(bootLayer, extraExports, false);
+        }
 
-        // decode the command line options
-        Map<String, Set<String>> map = decode("jdk.module.addexports.");
+        // --add-opens
+        prefix = "jdk.module.addopens.";
+        Map<String, List<String>> extraOpens = decode(prefix);
+        if (!extraOpens.isEmpty()) {
+            addExtraExportsOrOpens(bootLayer, extraOpens, true);
+        }
+    }
 
-        for (Map.Entry<String, Set<String>> e : map.entrySet()) {
+    private static void addExtraExportsOrOpens(Layer bootLayer,
+                                               Map<String, List<String>> map,
+                                               boolean opens)
+    {
+        for (Map.Entry<String, List<String>> e : map.entrySet()) {
 
             // the key is $MODULE/$PACKAGE
             String key = e.getKey();
@@ -507,28 +546,40 @@
                     }
                 }
                 if (allUnnamed) {
-                    Modules.addExportsToAllUnnamed(m, pn);
+                    if (opens) {
+                        Modules.addOpensToAllUnnamed(m, pn);
+                    } else {
+                        Modules.addExportsToAllUnnamed(m, pn);
+                    }
                 } else {
-                    Modules.addExports(m, pn, other);
+                    if (opens) {
+                        Modules.addOpens(m, pn, other);
+                    } else {
+                        Modules.addExports(m, pn, other);
+                    }
                 }
+
             }
         }
     }
 
-
     /**
-     * Decodes the values of --add-reads or --add-exports options
+     * Decodes the values of --add-reads, -add-exports, --add-opens or
+     * --patch-modules options that are encoded in system properties.
      *
-     * The format of the options is: $KEY=$MODULE(,$MODULE)*
+     * @param prefix the system property prefix
+     * @praam regex the regex for splitting the RHS of the option value
      */
-    private static Map<String, Set<String>> decode(String prefix) {
+    private static Map<String, List<String>> decode(String prefix,
+                                                    String regex,
+                                                    boolean allowDuplicates) {
         int index = 0;
         // the system property is removed after decoding
         String value = getAndRemoveProperty(prefix + index);
         if (value == null)
             return Collections.emptyMap();
 
-        Map<String, Set<String>> map = new HashMap<>();
+        Map<String, List<String>> map = new HashMap<>();
 
         while (value != null) {
 
@@ -545,8 +596,11 @@
             if (rhs.isEmpty())
                 fail("Unable to parse: " + value);
 
-            Set<String> values = map.computeIfAbsent(key, k -> new HashSet<>());
-            for (String s : rhs.split(",")) {
+            // value is <module>(,<module>)* or <file>(<pathsep><file>)*
+            if (!allowDuplicates && map.containsKey(key))
+                fail(key + " specified more than once");
+            List<String> values = map.computeIfAbsent(key, k -> new ArrayList<>());
+            for (String s : rhs.split(regex)) {
                 if (s.length() > 0) values.add(s);
             }
 
@@ -558,6 +612,14 @@
     }
 
     /**
+     * Decodes the values of --add-reads, -add-exports or --add-opens
+     * which use the "," to separate the RHS of the option value.
+     */
+    private static Map<String, List<String>> decode(String prefix) {
+        return decode(prefix, ",", true);
+    }
+
+    /**
      * Gets and remove the named system property
      */
     private static String getAndRemoveProperty(String key) {
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,7 +32,6 @@
 import java.nio.file.Path;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
-import java.util.Base64;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -45,23 +44,23 @@
 public final class ModuleHashes {
 
     /**
-     * A supplier of an encoded message digest.
+     * A supplier of a message digest.
      */
     public static interface HashSupplier {
-        String generate(String algorithm);
+        byte[] generate(String algorithm);
     }
 
 
     private final String algorithm;
-    private final Map<String, String> nameToHash;
+    private final Map<String, byte[]> nameToHash;
 
     /**
      * Creates a {@code ModuleHashes}.
      *
      * @param algorithm   the algorithm used to create the hashes
-     * @param nameToHash  the map of module name to hash value (in string form)
+     * @param nameToHash  the map of module name to hash value
      */
-    public ModuleHashes(String algorithm, Map<String, String> nameToHash) {
+    public ModuleHashes(String algorithm, Map<String, byte[]> nameToHash) {
         this.algorithm = algorithm;
         this.nameToHash = Collections.unmodifiableMap(nameToHash);
     }
@@ -81,28 +80,28 @@
     }
 
     /**
-     * Returns the hash string for the given module name, {@code null}
+     * Returns the hash for the given module name, {@code null}
      * if there is no hash recorded for the module.
      */
-    public String hashFor(String mn) {
+    public byte[] hashFor(String mn) {
         return nameToHash.get(mn);
     }
 
     /**
-     * Returns unmodifiable map of module name to hash string.
+     * Returns unmodifiable map of module name to hash
      */
-    public Map<String, String> hashes() {
+    public Map<String, byte[]> hashes() {
         return nameToHash;
     }
 
     /**
      * Computes the hash for the given file with the given message digest
-     * algorithm. Returns the results a base64-encoded String.
+     * algorithm.
      *
      * @throws UncheckedIOException if an I/O error occurs
      * @throws RuntimeException if the algorithm is not available
      */
-    public static String computeHashAsString(Path file, String algorithm) {
+    public static byte[] computeHash(Path file, String algorithm) {
         try {
             MessageDigest md = MessageDigest.getInstance(algorithm);
 
@@ -118,8 +117,7 @@
                 }
             }
 
-            byte[] bytes = md.digest();
-            return Base64.getEncoder().encodeToString(bytes);
+            return md.digest();
         } catch (NoSuchAlgorithmException e) {
             throw new RuntimeException(e);
         } catch (IOException ioe) {
@@ -133,14 +131,14 @@
      * the entry name, typically the module name. The map value is the file
      * path to the entry (module artifact).
      *
-     * @return ModuleHashes encapsulate the hashes
+     * @return ModuleHashes that encapsulates the hashes
      */
     public static ModuleHashes generate(Map<String, Path> map, String algorithm) {
-        Map<String, String> nameToHash = new HashMap<>();
+        Map<String, byte[]> nameToHash = new HashMap<>();
         for (Map.Entry<String, Path> entry: map.entrySet()) {
             String name = entry.getKey();
             Path path = entry.getValue();
-            nameToHash.put(name, computeHashAsString(path, algorithm));
+            nameToHash.put(name, computeHash(path, algorithm));
         }
         return new ModuleHashes(algorithm, nameToHash);
     }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Wed Jul 05 22:32:06 2017 +0200
@@ -53,8 +53,8 @@
     // the input stream to read the original module-info.class
     private final InputStream in;
 
-    // the packages in the ConcealedPackages attribute
-    private Set<String> conceals;
+    // the packages in the Packages attribute
+    private Set<String> packages;
 
     // the value of the Version attribute
     private Version version;
@@ -75,10 +75,10 @@
     }
 
     /**
-     * Sets the set of packages for the ConcealedPackages attribute
+     * Sets the set of packages for the Packages attribute
      */
-    public ModuleInfoExtender conceals(Set<String> packages) {
-        this.conceals = Collections.unmodifiableSet(packages);
+    public ModuleInfoExtender packages(Set<String> packages) {
+        this.packages = Collections.unmodifiableSet(packages);
         return this;
     }
 
@@ -181,26 +181,26 @@
 
         ClassReader cr = new ClassReader(in);
 
-        if (conceals != null)
-            cv.addAttribute(new ConcealedPackagesAttribute(conceals));
+        if (packages != null)
+            cv.addAttribute(new ModulePackagesAttribute(packages));
         if (version != null)
-            cv.addAttribute(new VersionAttribute(version));
+            cv.addAttribute(new ModuleVersionAttribute(version));
         if (mainClass != null)
-            cv.addAttribute(new MainClassAttribute(mainClass));
+            cv.addAttribute(new ModuleMainClassAttribute(mainClass));
         if (osName != null || osArch != null || osVersion != null)
-            cv.addAttribute(new TargetPlatformAttribute(osName, osArch, osVersion));
+            cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
         if (hashes != null)
-            cv.addAttribute(new HashesAttribute(hashes));
+            cv.addAttribute(new ModuleHashesAttribute(hashes));
 
         List<Attribute> attrs = new ArrayList<>();
 
         // prototypes of attributes that should be parsed
         attrs.add(new ModuleAttribute());
-        attrs.add(new ConcealedPackagesAttribute());
-        attrs.add(new VersionAttribute());
-        attrs.add(new MainClassAttribute());
-        attrs.add(new TargetPlatformAttribute());
-        attrs.add(new HashesAttribute());
+        attrs.add(new ModulePackagesAttribute());
+        attrs.add(new ModuleVersionAttribute());
+        attrs.add(new ModuleMainClassAttribute());
+        attrs.add(new ModuleTargetAttribute());
+        attrs.add(new ModuleHashesAttribute());
 
         cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
 
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,9 +27,8 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Version;
 import java.nio.ByteBuffer;
-import java.util.Optional;
+import java.util.stream.Stream;
 
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.Opcodes;
@@ -52,31 +51,28 @@
     private static byte[] toModuleInfo(ModuleDescriptor md) {
 
         ClassWriter cw = new ClassWriter(0);
-
-        String name = md.name().replace('.', '/') + "/module-info";
-        cw.visit(Opcodes.V1_9, ACC_MODULE, name, null, null, null);
-
+        cw.visit(Opcodes.V1_9, ACC_MODULE, null, null, null, null);
         cw.visitAttribute(new ModuleAttribute(md));
 
-        // for tests: write the ConcealedPackages attribute when there are non-exported packages
-        long nExportedPackages = md.exports().stream()
-                .map(ModuleDescriptor.Exports::source)
-                .distinct()
-                .count();
-        if (md.packages().size() > nExportedPackages)
-            cw.visitAttribute(new ConcealedPackagesAttribute(md.packages()));
+        // for tests: write the Packages attribute when there are packages that
+        // aren't exported or open
+        Stream<String> exported = md.exports().stream()
+                .map(ModuleDescriptor.Exports::source);
+        Stream<String> open = md.opens().stream()
+                .map(ModuleDescriptor.Opens::source);
+        long exportedOrOpen = Stream.concat(exported, open).distinct().count();
+        if (md.packages().size() > exportedOrOpen)
+            cw.visitAttribute(new ModulePackagesAttribute(md.packages()));
 
-        md.version().ifPresent(v -> cw.visitAttribute(new VersionAttribute(v)));
-        md.mainClass().ifPresent(mc -> cw.visitAttribute(new MainClassAttribute(mc)));
+        md.version().ifPresent(v -> cw.visitAttribute(new ModuleVersionAttribute(v)));
+        md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
 
         // write the TargetPlatform attribute if have any of OS name/arch/version
         String osName = md.osName().orElse(null);
         String osArch = md.osArch().orElse(null);
         String osVersion = md.osVersion().orElse(null);
         if (osName != null || osArch != null || osVersion != null) {
-            cw.visitAttribute(new TargetPlatformAttribute(osName,
-                                                          osArch,
-                                                          osVersion));
+            cw.visitAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
         }
 
         cw.visitEnd();
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Wed Jul 05 22:32:06 2017 +0200
@@ -50,6 +50,7 @@
 import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import jdk.internal.loader.Resource;
@@ -59,7 +60,7 @@
 
 
 /**
- * Provides support for patching modules in the boot layer with --patch-module.
+ * Provides support for patching modules, mostly the boot layer.
  */
 
 public final class ModulePatcher {
@@ -67,89 +68,46 @@
     private static final JavaLangModuleAccess JLMA
         = SharedSecrets.getJavaLangModuleAccess();
 
-    // the prefix of the system properties that encode the value of --patch-module
-    private static final String PATCH_PROPERTY_PREFIX = "jdk.module.patch.";
-
     // module name -> sequence of patches (directories or JAR files)
-    private static final Map<String, List<Path>> PATCH_MAP = decodeProperties();
-
-    private ModulePatcher() { }
+    private final Map<String, List<Path>> map;
 
     /**
-     * Decodes the values of --patch-module options, returning a Map of module
-     * name to list of file paths.
-     *
-     * @throws IllegalArgumentException if the the module name is missing or
-     *         --patch-module is used more than once to patch the same module
+     * Initialize the module patcher with the given map. The map key is
+     * the module name, the value is a list of path strings.
      */
-    private static Map<String, List<Path>> decodeProperties() {
-
-        int index = 0;
-        String value = getAndRemoveProperty(PATCH_PROPERTY_PREFIX + index);
-        if (value == null)
-            return Collections.emptyMap();  // --patch-module not specified
-
-        Map<String, List<Path>> map = new HashMap<>();
-        while (value != null) {
-
-            // <module>=<file>(:<file>)*
-
-            int pos = value.indexOf('=');
-            if (pos == -1)
-                throwIAE("Unable to parse: " + value);
-            if (pos == 0)
-                throwIAE("Missing module name: " + value);
-
-            String mn = value.substring(0, pos);
-            List<Path> list = map.get(mn);
-            if (list != null)
-                throwIAE("Module " + mn + " specified more than once");
-            list = new ArrayList<>();
-            map.put(mn, list);
-
-            String paths = value.substring(pos+1);
-            for (String path : paths.split(File.pathSeparator)) {
-                if (!path.isEmpty()) {
-                    list.add(Paths.get(path));
-                }
+    public ModulePatcher(Map<String, List<String>> input) {
+        if (input.isEmpty()) {
+            this.map = Collections.emptyMap();
+        } else {
+            Map<String, List<Path>> map = new HashMap<>();
+            for (Map.Entry<String, List<String>> e : input.entrySet()) {
+                String mn = e.getKey();
+                List<Path> paths = e.getValue().stream()
+                        .map(Paths::get)
+                        .collect(Collectors.toList());
+                map.put(mn, paths);
             }
-
-            index++;
-            value = getAndRemoveProperty(PATCH_PROPERTY_PREFIX + index);
+            this.map = map;
         }
-
-        return map;
-    }
-
-
-    /**
-     * Returns {@code true} is --patch-module is specified to patch modules
-     * in the boot layer.
-     */
-    static boolean isBootLayerPatched() {
-        return !PATCH_MAP.isEmpty();
     }
 
     /**
      * Returns a module reference that interposes on the given module if
      * needed. If there are no patches for the given module then the module
      * reference is simply returned. Otherwise the patches for the module
-     * are scanned (to find any new concealed packages) and a new module
-     * reference is returned.
+     * are scanned (to find any new packages) and a new module reference is
+     * returned.
      *
      * @throws UncheckedIOException if an I/O error is detected
      */
-    public static ModuleReference interposeIfNeeded(ModuleReference mref) {
-
+    public ModuleReference patchIfNeeded(ModuleReference mref) {
+        // if there are no patches for the module then nothing to do
         ModuleDescriptor descriptor = mref.descriptor();
         String mn = descriptor.name();
-
-        // if there are no patches for the module then nothing to do
-        List<Path> paths = PATCH_MAP.get(mn);
+        List<Path> paths = map.get(mn);
         if (paths == null)
             return mref;
 
-
         // scan the JAR file or directory tree to get the set of packages
         Set<String> packages = new HashSet<>();
         try {
@@ -197,6 +155,13 @@
 
     }
 
+    /**
+     * Returns true is this module patcher has no patches.
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
 
     /**
      * A ModuleReader that reads resources from a patched module.
@@ -569,13 +534,6 @@
     }
 
     /**
-     * Gets and remove the named system property
-     */
-    private static String getAndRemoveProperty(String key) {
-        return (String)System.getProperties().remove(key);
-    }
-
-    /**
      * Derives a package name from the name of an entry in a JAR file.
      */
     private static String toPackageName(Path file, JarEntry entry) {
@@ -593,9 +551,4 @@
             System.err.println("WARNING: " + e + " ignored in patch: " + file);
         return "";
     }
-
-    private static void throwIAE(String msg) {
-        throw new IllegalArgumentException(msg);
-    }
-
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,8 +26,11 @@
 package jdk.internal.module;
 
 import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.net.URI;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Set;
 
 import jdk.internal.loader.BootLoader;
@@ -35,7 +38,6 @@
 import jdk.internal.misc.JavaLangReflectModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 
-
 /**
  * A helper class to allow JDK classes create dynamic modules and to update
  * modules, exports and the readability graph. It is also invoked by the VM
@@ -53,7 +55,6 @@
     private static final JavaLangReflectModuleAccess JLRMA
         = SharedSecrets.getJavaLangReflectModuleAccess();
 
-
     /**
      * Creates a new Module. The module has the given ModuleDescriptor and
      * is defined to the given class loader.
@@ -72,7 +73,7 @@
 
     /**
      * Define a new module to the VM. The module has the given set of
-     * concealed packages and is defined to the given class loader.
+     * packages and is defined to the given class loader.
      *
      * The resulting Module is in a larval state in that it does not not read
      * any other module and does not have any exports.
@@ -81,8 +82,9 @@
                                       String name,
                                       Set<String> packages)
     {
-        ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder(name).conceals(packages).build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module(name)
+                .contains(packages)
+                .build();
 
         return JLRMA.defineModule(loader, descriptor, null);
     }
@@ -104,13 +106,21 @@
 
     /**
      * Updates module m1 to export a package to module m2.
-     * Same as m1.addExports(pkg, m2) but without a caller check.
+     * Same as m1.addExports(pn, m2) but without a caller check.
      */
     public static void addExports(Module m1, String pn, Module m2) {
         JLRMA.addExports(m1, pn, m2);
     }
 
     /**
+     * Updates module m1 to open a package to module m2.
+     * Same as m1.addOpens(pn, m2) but without a caller check.
+     */
+    public static void addOpens(Module m1, String pn, Module m2) {
+        JLRMA.addOpens(m1, pn, m2);
+    }
+
+    /**
      * Updates a module m to export a package to all modules.
      */
     public static void addExportsToAll(Module m, String pn) {
@@ -118,6 +128,13 @@
     }
 
     /**
+     * Updates a module m to open a package to all modules.
+     */
+    public static void addOpensToAll(Module m, String pn) {
+        JLRMA.addOpensToAll(m, pn);
+    }
+
+    /**
      * Updates module m to export a package to all unnamed modules.
      */
     public static void addExportsToAllUnnamed(Module m, String pn) {
@@ -125,6 +142,47 @@
     }
 
     /**
+     * Updates module m to open a package to all unnamed modules.
+     */
+    public static void addOpensToAllUnnamed(Module m, String pn) {
+        JLRMA.addOpensToAllUnnamed(m, pn);
+    }
+
+    /**
+     * Updates module m to use a service
+     */
+    public static void addUses(Module m, Class<?> service) {
+        JLRMA.addUses(m, service);
+    }
+
+    /**
+     * Updates module m to provide a service
+     */
+    public static void addProvides(Module m, Class<?> service, Class<?> impl) {
+        Layer layer = m.getLayer();
+
+        if (layer == null || layer == Layer.boot()) {
+            // update ClassLoader catalog
+            PrivilegedAction<ClassLoader> pa = m::getClassLoader;
+            ClassLoader loader = AccessController.doPrivileged(pa);
+            ServicesCatalog catalog;
+            if (loader == null) {
+                catalog = BootLoader.getServicesCatalog();
+            } else {
+                catalog = ServicesCatalog.getServicesCatalog(loader);
+            }
+            catalog.addProvider(m, service, impl);
+        }
+
+        if (layer != null) {
+            // update Layer catalog
+            SharedSecrets.getJavaLangReflectModuleAccess()
+                    .getServicesCatalog(layer)
+                    .addProvider(m, service, impl);
+        }
+    }
+
+    /**
      * Adds a package to a module's content.
      *
      * This method is a no-op if the module already contains the package.
@@ -142,5 +200,4 @@
         addReads(m, BootLoader.getUnnamedModule());
         addReads(m, ClassLoaders.appClassLoader().getUnnamedModule());
     }
-
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,20 +28,24 @@
 import java.lang.reflect.Module;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Provides;
+import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import jdk.internal.loader.ClassLoaderValue;
 
 /**
  * A <em>services catalog</em>. Each {@code ClassLoader} and {@code Layer} has
  * an optional {@code ServicesCatalog} for modules that provide services.
  *
- * @see java.util.ServiceLoader
+ * @apiNote This class will be replaced once the ServiceLoader is further
+ *          specified
  */
-public interface ServicesCatalog {
+public final class ServicesCatalog {
 
     /**
      * Represents a service provider in the services catalog.
@@ -78,56 +82,98 @@
         }
     }
 
-    /**
-     * Registers the providers in the given module in this services catalog.
-     *
-     * @throws UnsupportedOperationException
-     *         If this services catalog is immutable
-     */
-    void register(Module module);
+    // service name -> list of providers
+    private final Map<String, List<ServiceProvider>> map = new ConcurrentHashMap<>();
 
-    /**
-     * Returns the (possibly empty) set of service providers that implement the
-     * given service type.
-     */
-    Set<ServiceProvider> findServices(String service);
+    private ServicesCatalog() { }
 
     /**
      * Creates a ServicesCatalog that supports concurrent registration and
-     * and lookup.
+     * and lookup
+     */
+    public static ServicesCatalog create() {
+        return new ServicesCatalog();
+    }
+
+    /**
+     * Returns the list of service provides for the given service type
+     * name, creating it if needed.
      */
-    static ServicesCatalog create() {
-        return new ServicesCatalog() {
-
-            private Map<String, Set<ServiceProvider>> map = new ConcurrentHashMap<>();
+    private List<ServiceProvider> providers(String service) {
+        // avoid computeIfAbsent here
+        List<ServiceProvider> list = map.get(service);
+        if (list == null) {
+            list = new CopyOnWriteArrayList<>();
+            List<ServiceProvider> prev = map.putIfAbsent(service, list);
+            if (prev != null)
+                list = prev;  // someone else got there
+        }
+        return list;
+    }
 
-            @Override
-            public void register(Module m) {
-                ModuleDescriptor descriptor = m.getDescriptor();
-
-                for (Provides provides : descriptor.provides().values()) {
-                    String service = provides.service();
-                    Set<String> providerNames = provides.providers();
+    /**
+     * Registers the providers in the given module in this services catalog.
+     */
+    public void register(Module module) {
+        ModuleDescriptor descriptor = module.getDescriptor();
+        for (Provides provides : descriptor.provides()) {
+            String service = provides.service();
+            List<String> providerNames = provides.providers();
+            int count = providerNames.size();
+            if (count == 1) {
+                String pn = providerNames.get(0);
+                providers(service).add(new ServiceProvider(module, pn));
+            } else {
+                List<ServiceProvider> list = new ArrayList<>(count);
+                for (String pn : providerNames) {
+                    list.add(new ServiceProvider(module, pn));
+                }
+                providers(service).addAll(list);
+            }
+        }
+    }
 
-                    // create a new set to replace the existing
-                    Set<ServiceProvider> result = new HashSet<>();
-                    Set<ServiceProvider> providers = map.get(service);
-                    if (providers != null) {
-                        result.addAll(providers);
-                    }
-                    for (String pn : providerNames) {
-                        result.add(new ServiceProvider(m, pn));
-                    }
-                    map.put(service, Collections.unmodifiableSet(result));
-                }
+    /**
+     * Add a provider in the given module to this services catalog
+     *
+     * @apiNote This method is for use by java.lang.instrument
+     */
+    public void addProvider(Module module, Class<?> service, Class<?> impl) {
+        List<ServiceProvider> list = providers(service.getName());
+        list.add(new ServiceProvider(module, impl.getName()));
+    }
+
+    /**
+     * Returns the (possibly empty) list of service providers that implement
+     * the given service type.
+     */
+    public List<ServiceProvider> findServices(String service) {
+        return map.getOrDefault(service, Collections.emptyList());
+    }
 
-            }
+    /**
+     * Returns the ServicesCatalog for the given class loader or {@code null}
+     * if there is none.
+     */
+    public static ServicesCatalog getServicesCatalogOrNull(ClassLoader loader) {
+        return CLV.get(loader);
+    }
 
-            @Override
-            public Set<ServiceProvider> findServices(String service) {
-                return map.getOrDefault(service, Collections.emptySet());
-            }
+    /**
+     * Returns the ServicesCatalog for the given class loader, creating it if
+     * needed.
+     */
+    public static ServicesCatalog getServicesCatalog(ClassLoader loader) {
+        // CLV.computeIfAbsent(loader, (cl, clv) -> create());
+        ServicesCatalog catalog = CLV.get(loader);
+        if (catalog == null) {
+            catalog = create();
+            ServicesCatalog previous = CLV.putIfAbsent(loader, catalog);
+            if (previous != null) catalog = previous;
+        }
+        return catalog;
+    }
 
-        };
-    }
+    // the ServicesCatalog registered to a class loader
+    private static final ClassLoaderValue<ServicesCatalog> CLV = new ClassLoaderValue<>();
 }
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Wed Jul 05 22:32:06 2017 +0200
@@ -51,7 +51,7 @@
     /**
      * Hash of system modules.
      */
-    public static String[] MODULES_TO_HASH = new String[0];
+    public static byte[][] MODULES_TO_HASH = new byte[0][];
 
     /**
      * Number of packages in the boot layer from the installed modules.
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java	Wed Jul 05 22:32:06 2017 +0200
@@ -695,7 +695,7 @@
             final String[] interfaces) {
         this.version = version;
         this.access = access;
-        this.name = newClass(name);
+        this.name = (name == null) ? 0 : newClass(name);
         thisName = name;
         if (ClassReader.SIGNATURES && signature != null) {
             this.signature = newUTF8(signature);
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Wed Jul 05 22:32:06 2017 +0200
@@ -112,10 +112,13 @@
         }
     }
 
-    private static boolean verifyMemberAccess(Class<?> currentClass,
-                                              Class<?> memberClass,
-                                              Class<?> targetClass,
-                                              int modifiers)
+    /**
+     * Verify access to a member, returning {@code false} if no access
+     */
+    public static boolean verifyMemberAccess(Class<?> currentClass,
+                                             Class<?> memberClass,
+                                             Class<?> targetClass,
+                                             int modifiers)
     {
         // Verify that currentClass can access a field, method, or
         // constructor of memberClass, where that member's access bits are
--- a/jdk/src/java.base/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -115,16 +115,16 @@
     // additional qualified exports may be inserted at build time
     // see make/gensrc/GenModuleInfo.gmk
 
-    // CORBA serialization needs reflective access
-    exports sun.util.calendar to
-        java.corba;
-
     exports com.sun.security.ntlm to
         java.security.sasl;
     exports jdk.internal.jimage to
         jdk.jlink;
     exports jdk.internal.jimage.decompressor to
         jdk.jlink;
+    exports jdk.internal.loader to
+        java.instrument,
+        java.logging,
+        jdk.jlink;
     exports jdk.internal.jmod to
         jdk.compiler,
         jdk.jlink;
@@ -146,9 +146,6 @@
         jdk.scripting.nashorn;
     exports jdk.internal.org.objectweb.asm.signature to
         jdk.scripting.nashorn;
-    exports jdk.internal.loader to
-        java.instrument,
-        java.logging;
     exports jdk.internal.math to
         java.desktop;
     exports jdk.internal.module to
@@ -307,6 +304,8 @@
     // JDK-internal service types
     uses jdk.internal.logger.DefaultLoggerFinder;
     uses sun.security.ssl.ClientKeyExchangeService;
+    uses sun.security.util.AuthResourcesProvider;
+    uses sun.text.spi.JavaTimeDateTimePatternProvider;
     uses sun.util.spi.CalendarProvider;
     uses sun.util.locale.provider.LocaleDataMetaInfo;
     uses sun.util.resources.LocaleData.CommonResourceBundleProvider;
@@ -317,4 +316,6 @@
 
     provides java.nio.file.spi.FileSystemProvider with
         jdk.internal.jrtfs.JrtFileSystemProvider;
+    provides sun.security.util.AuthResourcesProvider with
+        sun.security.util.AuthResourcesProviderImpl;
 }
--- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -48,6 +48,7 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Method;
@@ -62,24 +63,29 @@
 import java.nio.file.Path;
 import java.text.Normalizer;
 import java.text.MessageFormat;
-import java.util.ResourceBundle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale.Category;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Properties;
-import java.util.Map;
+import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 import jdk.internal.misc.VM;
+import jdk.internal.module.Modules;
 
 
 public final class LauncherHelper {
@@ -95,6 +101,8 @@
     private static final String JAVAFX_FXHELPER_CLASS_NAME_SUFFIX =
             "sun.launcher.LauncherHelper$FXHelper";
     private static final String MAIN_CLASS = "Main-Class";
+    private static final String ADD_EXPORTS = "Add-Exports";
+    private static final String ADD_OPENS = "Add-Opens";
 
     private static StringBuilder outBuf = new StringBuilder();
 
@@ -413,11 +421,23 @@
             if (mainAttrs == null) {
                 abort(null, "java.launcher.jar.error3", jarname);
             }
+
+            // Main-Class
             mainValue = mainAttrs.getValue(MAIN_CLASS);
             if (mainValue == null) {
                 abort(null, "java.launcher.jar.error3", jarname);
             }
 
+            // Add-Exports and Add-Opens to break encapsulation
+            String exports = mainAttrs.getValue(ADD_EXPORTS);
+            if (exports != null) {
+                addExportsOrOpens(exports, false);
+            }
+            String opens = mainAttrs.getValue(ADD_OPENS);
+            if (opens != null) {
+                addExportsOrOpens(opens, true);
+            }
+
             /*
              * Hand off to FXHelper if it detects a JavaFX application
              * This must be done after ensuring a Main-Class entry
@@ -436,6 +456,29 @@
         return null;
     }
 
+    /**
+     * Process the Add-Exports or Add-Opens value. The value is
+     * {@code <module>/<package> ( <module>/<package>)*}.
+     */
+    static void addExportsOrOpens(String value, boolean open) {
+        for (String moduleAndPackage : value.split(" ")) {
+            String[] s = moduleAndPackage.trim().split("/");
+            if (s.length == 2) {
+                String mn = s[0];
+                String pn = s[1];
+                Layer.boot().findModule(mn).ifPresent(m -> {
+                    if (m.getDescriptor().packages().contains(pn)) {
+                        if (open) {
+                            Modules.addOpensToAllUnnamed(m, pn);
+                        } else {
+                            Modules.addExportsToAllUnnamed(m, pn);
+                        }
+                    }
+                });
+            }
+        }
+    }
+
     // From src/share/bin/java.c:
     //   enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR, LM_MODULE }
 
@@ -904,12 +947,26 @@
             for (String name: names) {
                 ModuleReference mref = finder.find(name).orElse(null);
                 if (mref == null) {
-                    // not found
+                    System.err.format("%s not observable!%n", name);
                     continue;
                 }
 
                 ModuleDescriptor md = mref.descriptor();
-                ostream.println(midAndLocation(md, mref.location()));
+                if (md.isOpen())
+                    ostream.print("open ");
+                if (md.isAutomatic())
+                    ostream.print("automatic ");
+                ostream.println("module " + midAndLocation(md, mref.location()));
+
+                // unqualified exports (sorted by package)
+                Set<Exports> exports = new TreeSet<>(Comparator.comparing(Exports::source));
+                md.exports().stream().filter(e -> !e.isQualified()).forEach(exports::add);
+                for (Exports e : exports) {
+                    String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
+                            Stream.of(e.source()))
+                            .collect(Collectors.joining(" "));
+                    ostream.format("  exports %s%n", modsAndSource);
+                }
 
                 for (Requires d : md.requires()) {
                     ostream.format("  requires %s%n", d);
@@ -918,31 +975,51 @@
                     ostream.format("  uses %s%n", s);
                 }
 
-                // sorted exports
-                Set<Exports> exports = new TreeSet<>(Comparator.comparing(Exports::source));
-                exports.addAll(md.exports());
-                for (Exports e : exports) {
-                    ostream.format("  exports %s", e.source());
+                for (Provides ps : md.provides()) {
+                    ostream.format("  provides %s with %s%n", ps.service(),
+                            ps.providers().stream().collect(Collectors.joining(", ")));
+                }
+
+                // qualified exports
+                for (Exports e : md.exports()) {
                     if (e.isQualified()) {
+                        String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
+                                Stream.of(e.source()))
+                                .collect(Collectors.joining(" "));
+                        ostream.format("  exports %s", modsAndSource);
                         formatCommaList(ostream, " to", e.targets());
-                    } else {
-                        ostream.println();
                     }
                 }
 
-                // concealed packages
-                new TreeSet<>(md.conceals())
-                    .forEach(p -> ostream.format("  conceals %s%n", p));
+                // open packages
+                for (Opens obj: md.opens()) {
+                    String modsAndSource = Stream.concat(toStringStream(obj.modifiers()),
+                            Stream.of(obj.source()))
+                            .collect(Collectors.joining(" "));
+                    ostream.format("  opens %s", modsAndSource);
+                    if (obj.isQualified())
+                        formatCommaList(ostream, " to", obj.targets());
+                    else
+                        ostream.println();
+                }
 
-                Map<String, Provides> provides = md.provides();
-                for (Provides ps : provides.values()) {
-                    for (String impl : ps.providers())
-                        ostream.format("  provides %s with %s%n", ps.service(), impl);
-                }
+                // non-exported/non-open packages
+                Set<String> concealed = new TreeSet<>(md.packages());
+                md.exports().stream().map(Exports::source).forEach(concealed::remove);
+                md.opens().stream().map(Opens::source).forEach(concealed::remove);
+                concealed.forEach(p -> ostream.format("  contains %s%n", p));
             }
         }
     }
 
+    static <T> String toString(Set<T> s) {
+        return toStringStream(s).collect(Collectors.joining(" "));
+    }
+
+    static <T> Stream<String> toStringStream(Set<T> s) {
+        return s.stream().map(e -> e.toString().toLowerCase());
+    }
+
     static String midAndLocation(ModuleDescriptor md, Optional<URI> location ) {
         URI loc = location.orElse(null);
         if (loc == null || loc.getScheme().equalsIgnoreCase("jrt"))
--- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -28,8 +28,8 @@
 \           (to execute a class)\n   or  {0} [options] -jar jarfile [args...]\n\
 \           (to execute a jar file)\n\
 \   or  {0} [options] -p <modulepath> -m <modulename>[/<mainclass>] [args...]\n\
-\           (to execute the main class in a module)\n\
-where options include:\n
+\           (to execute the main class in a module)\n\n\
+where options include:\n\n
 
 java.launcher.opt.datamodel  =\    -d{0}\t  Deprecated, will be removed in a future release\n
 java.launcher.opt.vmselect   =\    {0}\t  to select the "{1}" VM\n
@@ -68,11 +68,16 @@
 \                  set a system property\n\
 \    -verbose:[class|gc|jni]\n\
 \                  enable verbose output\n\
-\    -version      print product version and exit\n\
-\    -showversion  print product version and continue\n\
-\    -? -help --help\n\
-\                  print this help message\n\
-\    -X            print help on non-standard options\n\
+\    -version      print product version to the error stream and exit\n\
+\    --version     print product version to the output stream and exit\n\
+\    -showversion  print product version to the error stream and continue\n\
+\    --show-version\n\
+\                  print product version to the output stream and continue\n\
+\    -? -h -help\n\
+\                  print this help message to the error stream\n\
+\    --help        print this help message to the output stream\n\
+\    -X            print help on extra options to the error stream\n\
+\    --help-extra  print help on extra options to the output stream\n\
 \    -ea[:<packagename>...|:<classname>]\n\
 \    -enableassertions[:<packagename>...|:<classname>]\n\
 \                  enable assertions with specified granularity\n\
@@ -98,14 +103,12 @@
 \                  The most appropriate scaled image provided will be picked up\n\
 \                  automatically.\n\
 \                  See the SplashScreen API documentation for more information.\n\
-\    @<filepath>   read options from the specified file\n\
+\    @<filepath>   read options from the specified file\n\n\
 \To specify an argument for a long option, you can use --<name>=<value> or\n\
-\--<name> <value>.\n\
-
-See http://www.oracle.com/technetwork/java/javase/documentation/index.html for more details.
+\--<name> <value>.\n
 
 # Translators please note do not translate the options themselves
-java.launcher.X.usage=\
+java.launcher.X.usage=\n\
 \    -Xbatch           disable background compilation\n\
 \    -Xbootclasspath/a:<directories and zip/jar files separated by {0}>\n\
 \                      append to end of bootstrap class path\n\
@@ -152,10 +155,13 @@
 \                      regardless of module declaration.\n\
 \                      <target-module> can be ALL-UNNAMED to export to all\n\
 \                      unnamed modules.\n\
+\    --add-opens <module>/<package>=<target-module>(,<target-module>)*\n\
+\                      updates <module> to open <package> to\n\
+\                      <target-module>, regardless of module declaration.\n\
 \    --patch-module <module>=<file>({0}<file>)*\n\
 \                      Override or augment a module with classes and resources\n\
 \                      in JAR files or directories.\n\n\
-These options are non-standard and subject to change without notice.\n
+These extra options are subject to change without notice.\n
 
 # Translators please note do not translate the options themselves
 java.launcher.X.macosx.usage=\
--- a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,7 @@
 import java.io.*;
 import java.net.*;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.Properties;
 import sun.net.NetworkClient;
 import sun.net.ProgressSource;
@@ -35,6 +36,7 @@
 import sun.net.www.HeaderParser;
 import sun.net.www.MeteredStream;
 import sun.net.www.ParseUtil;
+import sun.net.www.protocol.http.AuthenticatorKeys;
 import sun.net.www.protocol.http.HttpURLConnection;
 import sun.util.logging.PlatformLogger;
 import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*;
@@ -132,6 +134,8 @@
         }
     }
 
+    protected volatile String authenticatorKey;
+
     /**
      * A NOP method kept for backwards binary compatibility
      * @deprecated -- system properties are no longer cached.
@@ -279,10 +283,12 @@
                     ret = null;
                 }
             }
-
             if (ret != null) {
-                if ((ret.proxy != null && ret.proxy.equals(p)) ||
-                    (ret.proxy == null && p == null)) {
+                String ak = httpuc == null ? AuthenticatorKeys.DEFAULT
+                     : httpuc.getAuthenticatorKey();
+                boolean compatible = Objects.equals(ret.proxy, p)
+                     && Objects.equals(ret.getAuthenticatorKey(), ak);
+                if (compatible) {
                     synchronized (ret) {
                         ret.cachedHttpClient = true;
                         assert ret.inCache;
@@ -306,6 +312,9 @@
         }
         if (ret == null) {
             ret = new HttpClient(url, p, to);
+            if (httpuc != null) {
+                ret.authenticatorKey = httpuc.getAuthenticatorKey();
+            }
         } else {
             SecurityManager security = System.getSecurityManager();
             if (security != null) {
@@ -341,6 +350,12 @@
             to, useCache, httpuc);
     }
 
+    public final String getAuthenticatorKey() {
+        String k = authenticatorKey;
+        if (k == null) return AuthenticatorKeys.DEFAULT;
+        return k;
+    }
+
     /* return it to the cache as still usable, if:
      * 1) It's keeping alive, AND
      * 2) It still has some connections left, AND
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthCache.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthCache.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,7 +38,8 @@
     /**
      * Put an entry in the cache. pkey is a string specified as follows:
      *
-     * A:[B:]C:D:E[:F]   Between 4 and 6 fields separated by ":"
+     * A:[B:]C:D:E[:F][;key=value]   Between 4 and 6 fields separated by ":",
+     *          and an optional semicolon-separated key=value list postfix,
      *          where the fields have the following meaning:
      * A is "s" or "p" for server or proxy authentication respectively
      * B is optional and is the {@link AuthScheme}, e.g. BASIC, DIGEST, NTLM, etc
@@ -47,6 +48,11 @@
      * E is the port number
      * F is optional and if present is the realm
      *
+     * The semi-colon separated key=value list postfix can be used to
+     * provide additional contextual information, thus allowing
+     * to separate AuthCacheValue instances obtained from different
+     * contexts.
+     *
      * Generally, two entries are created for each AuthCacheValue,
      * one including the realm and one without the realm.
      * Also, for some schemes (digest) multiple entries may be created
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -30,6 +30,7 @@
 import java.net.PasswordAuthentication;
 import java.net.URL;
 import java.util.HashMap;
+import java.util.Objects;
 
 import sun.net.www.HeaderParser;
 
@@ -190,8 +191,18 @@
     /** The shortest path from the URL we authenticated against. */
     String path;
 
+    /**
+     * A key identifying the authenticator from which the credentials
+     * were obtained.
+     * {@link AuthenticatorKeys#DEFAULT} identifies the {@linkplain
+     * java.net.Authenticator#setDefault(java.net.Authenticator) default}
+     * authenticator.
+     */
+     String authenticatorKey;
+
     /** Use this constructor only for proxy entries */
-    public AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) {
+    public AuthenticationInfo(char type, AuthScheme authScheme, String host,
+                              int port, String realm, String authenticatorKey) {
         this.type = type;
         this.authScheme = authScheme;
         this.protocol = "";
@@ -199,6 +210,7 @@
         this.port = port;
         this.realm = realm;
         this.path = null;
+        this.authenticatorKey = Objects.requireNonNull(authenticatorKey);
     }
 
     public Object clone() {
@@ -214,7 +226,8 @@
      * Constructor used to limit the authorization to the path within
      * the URL. Use this constructor for origin server entries.
      */
-    public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) {
+    public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm,
+                              String authenticatorKey) {
         this.type = type;
         this.authScheme = authScheme;
         this.protocol = url.getProtocol().toLowerCase();
@@ -231,7 +244,16 @@
         else {
             this.path = reducePath (urlPath);
         }
+        this.authenticatorKey = Objects.requireNonNull(authenticatorKey);
+    }
 
+    /**
+     * The {@linkplain java.net.Authenticator#getKey(java.net.Authenticator) key}
+     * of the authenticator that was used to obtain the credentials.
+     * @return The authenticator's key.
+     */
+    public final String getAuthenticatorKey() {
+        return authenticatorKey;
     }
 
     /*
@@ -256,13 +278,14 @@
      * don't yet know the realm
      * (i.e. when we're preemptively setting the auth).
      */
-    static AuthenticationInfo getServerAuth(URL url) {
+    static AuthenticationInfo getServerAuth(URL url, String authenticatorKey) {
         int port = url.getPort();
         if (port == -1) {
             port = url.getDefaultPort();
         }
         String key = SERVER_AUTHENTICATION + ":" + url.getProtocol().toLowerCase()
-                + ":" + url.getHost().toLowerCase() + ":" + port;
+                + ":" + url.getHost().toLowerCase() + ":" + port
+                + ";auth=" + authenticatorKey;
         return getAuth(key, url);
     }
 
@@ -272,13 +295,17 @@
      * In this case we do not use the path because the protection space
      * is identified by the host:port:realm only
      */
-    static String getServerAuthKey(URL url, String realm, AuthScheme scheme) {
+    static String getServerAuthKey(URL url, String realm, AuthScheme scheme,
+                                   String authenticatorKey) {
         int port = url.getPort();
         if (port == -1) {
             port = url.getDefaultPort();
         }
-        String key = SERVER_AUTHENTICATION + ":" + scheme + ":" + url.getProtocol().toLowerCase()
-                     + ":" + url.getHost().toLowerCase() + ":" + port + ":" + realm;
+        String key = SERVER_AUTHENTICATION + ":" + scheme + ":"
+                     + url.getProtocol().toLowerCase()
+                     + ":" + url.getHost().toLowerCase()
+                     + ":" + port + ":" + realm
+                     + ";auth=" + authenticatorKey;
         return key;
     }
 
@@ -309,8 +336,10 @@
      * for preemptive header-setting. Note, the protocol field is always
      * blank for proxies.
      */
-    static AuthenticationInfo getProxyAuth(String host, int port) {
-        String key = PROXY_AUTHENTICATION + "::" + host.toLowerCase() + ":" + port;
+    static AuthenticationInfo getProxyAuth(String host, int port,
+                                           String authenticatorKey) {
+        String key = PROXY_AUTHENTICATION + "::" + host.toLowerCase() + ":" + port
+                     + ";auth=" + authenticatorKey;
         AuthenticationInfo result = (AuthenticationInfo) cache.get(key, null);
         return result;
     }
@@ -320,9 +349,12 @@
      * Used in response to a challenge. Note, the protocol field is always
      * blank for proxies.
      */
-    static String getProxyAuthKey(String host, int port, String realm, AuthScheme scheme) {
-        String key = PROXY_AUTHENTICATION + ":" + scheme + "::" + host.toLowerCase()
-                        + ":" + port + ":" + realm;
+    static String getProxyAuthKey(String host, int port, String realm,
+                                  AuthScheme scheme, String authenticatorKey) {
+        String key = PROXY_AUTHENTICATION + ":" + scheme
+                        + "::" + host.toLowerCase()
+                        + ":" + port + ":" + realm
+                        + ";auth=" + authenticatorKey;
         return key;
     }
 
@@ -424,27 +456,34 @@
     String cacheKey(boolean includeRealm) {
         // This must be kept in sync with the getXXXAuth() methods in this
         // class.
+        String authenticatorKey = getAuthenticatorKey();
         if (includeRealm) {
             return type + ":" + authScheme + ":" + protocol + ":"
-                        + host + ":" + port + ":" + realm;
+                        + host + ":" + port + ":" + realm
+                     + ";auth=" + authenticatorKey;
         } else {
-            return type + ":" + protocol + ":" + host + ":" + port;
+            return type + ":" + protocol + ":" + host + ":" + port
+                     + ";auth=" + authenticatorKey;
         }
     }
 
     String s1, s2;  /* used for serialization of pw */
 
-    private void readObject(ObjectInputStream s)
+    private synchronized void readObject(ObjectInputStream s)
         throws IOException, ClassNotFoundException
     {
         s.defaultReadObject ();
         pw = new PasswordAuthentication (s1, s2.toCharArray());
         s1 = null; s2= null;
+        if (authenticatorKey == null) {
+            authenticatorKey = AuthenticatorKeys.DEFAULT;
+        }
     }
 
     private synchronized void writeObject(java.io.ObjectOutputStream s)
         throws IOException
     {
+        Objects.requireNonNull(authenticatorKey);
         s1 = pw.getUserName();
         s2 = new String (pw.getPassword());
         s.defaultWriteObject ();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticatorKeys.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,76 @@
+/*
+ * 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 sun.net.www.protocol.http;
+
+import java.net.Authenticator;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ *  A class used to tie a key to an authenticator instance.
+ */
+public final class AuthenticatorKeys {
+    private AuthenticatorKeys() {
+        throw new InternalError("Trying to instantiate static class");
+    }
+
+    public static final String DEFAULT = "default";
+    private static final AtomicLong IDS = new AtomicLong();
+
+    public static String computeKey(Authenticator a) {
+        return System.identityHashCode(a) + "-" + IDS.incrementAndGet()
+               + "@" + a.getClass().getName();
+    }
+
+    /**
+     * Returns a key for the given authenticator.
+     *
+     * @param authenticator The authenticator; {@code null} should be
+     *        passed when the {@linkplain
+     *        Authenticator#setDefault(java.net.Authenticator) default}
+     *        authenticator is meant.
+     * @return A key for the given authenticator, {@link #DEFAULT} for
+     *         {@code null}.
+     */
+    public static String getKey(Authenticator authenticator) {
+        if (authenticator == null) {
+            return DEFAULT;
+        }
+        return authenticatorKeyAccess.getKey(authenticator);
+    }
+
+    @FunctionalInterface
+    public interface AuthenticatorKeyAccess {
+        public String getKey(Authenticator a);
+    }
+
+    private static AuthenticatorKeyAccess authenticatorKeyAccess;
+    public static void setAuthenticatorKeyAccess(AuthenticatorKeyAccess access) {
+        if (authenticatorKeyAccess == null && access != null) {
+            authenticatorKeyAccess = access;
+        }
+    }
+
+}
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Base64;
+import java.util.Objects;
 import sun.net.www.HeaderParser;
 
 /**
@@ -54,9 +55,11 @@
      * Create a BasicAuthentication
      */
     public BasicAuthentication(boolean isProxy, String host, int port,
-                               String realm, PasswordAuthentication pw) {
+                               String realm, PasswordAuthentication pw,
+                               String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              AuthScheme.BASIC, host, port, realm);
+              AuthScheme.BASIC, host, port, realm,
+              Objects.requireNonNull(authenticatorKey));
         String plain = pw.getUserName() + ":";
         byte[] nameBytes = null;
         try {
@@ -84,9 +87,11 @@
      * Create a BasicAuthentication
      */
     public BasicAuthentication(boolean isProxy, String host, int port,
-                               String realm, String auth) {
+                               String realm, String auth,
+                               String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              AuthScheme.BASIC, host, port, realm);
+              AuthScheme.BASIC, host, port, realm,
+              Objects.requireNonNull(authenticatorKey));
         this.auth = "Basic " + auth;
     }
 
@@ -94,9 +99,11 @@
      * Create a BasicAuthentication
      */
     public BasicAuthentication(boolean isProxy, URL url, String realm,
-                                   PasswordAuthentication pw) {
+                               PasswordAuthentication pw,
+                               String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              AuthScheme.BASIC, url, realm);
+              AuthScheme.BASIC, url, realm,
+              Objects.requireNonNull(authenticatorKey));
         String plain = pw.getUserName() + ":";
         byte[] nameBytes = null;
         try {
@@ -124,9 +131,10 @@
      * Create a BasicAuthentication
      */
     public BasicAuthentication(boolean isProxy, URL url, String realm,
-                                   String auth) {
+                               String auth, String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              AuthScheme.BASIC, url, realm);
+              AuthScheme.BASIC, url, realm,
+              Objects.requireNonNull(authenticatorKey));
         this.auth = "Basic " + auth;
     }
 
@@ -202,4 +210,3 @@
         return npath;
     }
 }
-
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,6 +38,7 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivilegedAction;
 import java.security.AccessController;
+import java.util.Objects;
 import static sun.net.www.protocol.http.HttpURLConnection.HTTP_CONNECT;
 
 /**
@@ -193,11 +194,12 @@
      */
     public DigestAuthentication(boolean isProxy, URL url, String realm,
                                 String authMethod, PasswordAuthentication pw,
-                                Parameters params) {
+                                Parameters params, String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
               AuthScheme.DIGEST,
               url,
-              realm);
+              realm,
+              Objects.requireNonNull(authenticatorKey));
         this.authMethod = authMethod;
         this.pw = pw;
         this.params = params;
@@ -205,12 +207,13 @@
 
     public DigestAuthentication(boolean isProxy, String host, int port, String realm,
                                 String authMethod, PasswordAuthentication pw,
-                                Parameters params) {
+                                Parameters params, String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
               AuthScheme.DIGEST,
               host,
               port,
-              realm);
+              realm,
+              Objects.requireNonNull(authenticatorKey));
         this.authMethod = authMethod;
         this.pw = pw;
         this.params = params;
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -25,6 +25,7 @@
 
 package sun.net.www.protocol.http;
 
+import java.net.Authenticator;
 import java.net.Authenticator.RequestorType;
 import java.net.InetAddress;
 import java.net.URL;
@@ -49,6 +50,7 @@
     public final int port;
     public final InetAddress addr;
     public final RequestorType authType;
+    public final Authenticator authenticator;
 
     /**
      * Create a schemed object based on an un-schemed one.
@@ -62,12 +64,13 @@
         this.addr = old.addr;
         this.authType = old.authType;
         this.scheme = scheme;
+        this.authenticator =  old.authenticator;
     }
 
     /**
      * Constructor an un-schemed object for site access.
      */
-    public HttpCallerInfo(URL url) {
+    public HttpCallerInfo(URL url, Authenticator a) {
         this.url= url;
         prompt = "";
         host = url.getHost();
@@ -90,12 +93,13 @@
         protocol = url.getProtocol();
         authType = RequestorType.SERVER;
         scheme = "";
+        authenticator = a;
     }
 
     /**
      * Constructor an un-schemed object for proxy access.
      */
-    public HttpCallerInfo(URL url, String host, int port) {
+    public HttpCallerInfo(URL url, String host, int port, Authenticator a) {
         this.url= url;
         this.host = host;
         this.port = port;
@@ -104,5 +108,6 @@
         protocol = url.getProtocol();
         authType = RequestorType.PROXY;
         scheme = "";
+        authenticator = a;
     }
 }
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -78,6 +78,7 @@
 import java.util.TimeZone;
 import java.net.MalformedURLException;
 import java.nio.ByteBuffer;
+import java.util.Objects;
 import java.util.Properties;
 import static sun.net.www.protocol.http.AuthScheme.BASIC;
 import static sun.net.www.protocol.http.AuthScheme.DIGEST;
@@ -304,6 +305,8 @@
     protected HttpClient http;
     protected Handler handler;
     protected Proxy instProxy;
+    protected volatile Authenticator authenticator;
+    protected volatile String authenticatorKey;
 
     private CookieHandler cookieHandler;
     private final ResponseCache cacheHandler;
@@ -433,6 +436,7 @@
      */
     private static PasswordAuthentication
     privilegedRequestPasswordAuthentication(
+                            final Authenticator authenticator,
                             final String host,
                             final InetAddress addr,
                             final int port,
@@ -448,7 +452,7 @@
                         logger.finest("Requesting Authentication: host =" + host + " url = " + url);
                     }
                     PasswordAuthentication pass = Authenticator.requestPasswordAuthentication(
-                        host, addr, port, protocol,
+                        authenticator, host, addr, port, protocol,
                         prompt, scheme, url, authType);
                     if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
                         logger.finest("Authentication returned: " + (pass != null ? pass.toString() : "null"));
@@ -507,6 +511,22 @@
         this.authObj = authObj;
     }
 
+    @Override
+    public synchronized void setAuthenticator(Authenticator auth) {
+        if (connecting || connected) {
+            throw new IllegalStateException(
+                  "Authenticator must be set before connecting");
+        }
+        authenticator = Objects.requireNonNull(auth);
+        authenticatorKey = AuthenticatorKeys.getKey(authenticator);
+    }
+
+    public String getAuthenticatorKey() {
+        String k = authenticatorKey;
+        if (k == null) return AuthenticatorKeys.getKey(authenticator);
+        return k;
+    }
+
     /*
      * checks the validity of http message header and throws
      * IllegalArgumentException if invalid.
@@ -631,7 +651,8 @@
                 requests.setIfNotSet("If-Modified-Since", fo.format(date));
             }
             // check for preemptive authorization
-            AuthenticationInfo sauth = AuthenticationInfo.getServerAuth(url);
+            AuthenticationInfo sauth = AuthenticationInfo.getServerAuth(url,
+                                             getAuthenticatorKey());
             if (sauth != null && sauth.supportsPreemptiveAuthorization() ) {
                 // Sets "Authorization"
                 requests.setIfNotSet(sauth.getHeaderName(), sauth.getHeaderValue(url,method));
@@ -800,15 +821,15 @@
      *        if present
      */
     protected void setProxiedClient (URL url,
-                                           String proxyHost, int proxyPort,
-                                           boolean useCache)
+                                     String proxyHost, int proxyPort,
+                                     boolean useCache)
         throws IOException {
         proxiedConnect(url, proxyHost, proxyPort, useCache);
     }
 
     protected void proxiedConnect(URL url,
-                                           String proxyHost, int proxyPort,
-                                           boolean useCache)
+                                  String proxyHost, int proxyPort,
+                                  boolean useCache)
         throws IOException {
         http = HttpClient.New (url, proxyHost, proxyPort, useCache,
             connectTimeout, this);
@@ -878,10 +899,14 @@
         boolean redir;
         int redirects = 0;
         InputStream in;
+        Authenticator a = null;
 
         do {
             if (c instanceof HttpURLConnection) {
                 ((HttpURLConnection) c).setInstanceFollowRedirects(false);
+                if (a == null) {
+                    a = ((HttpURLConnection) c).authenticator;
+                }
             }
 
             // We want to open the input stream before
@@ -912,6 +937,9 @@
                     }
                     redir = true;
                     c = target.openConnection();
+                    if (a != null && c instanceof HttpURLConnection) {
+                        ((HttpURLConnection)c).setAuthenticator(a);
+                    }
                     redirects++;
                 }
             }
@@ -1612,7 +1640,8 @@
                             responses,
                             new HttpCallerInfo(url,
                                                http.getProxyHostUsed(),
-                                               http.getProxyPortUsed()),
+                                               http.getProxyPortUsed(),
+                                               authenticator),
                             dontUseNegotiate,
                             disabledProxyingSchemes
                     );
@@ -1684,7 +1713,7 @@
 
                     srvHdr = new AuthenticationHeader (
                             "WWW-Authenticate", responses,
-                            new HttpCallerInfo(url),
+                            new HttpCallerInfo(url, authenticator),
                             dontUseNegotiate
                     );
 
@@ -1762,7 +1791,8 @@
                                 /* path could be an abs_path or a complete URI */
                                 URL u = new URL (url, path);
                                 DigestAuthentication d = new DigestAuthentication (
-                                                   false, u, realm, "Digest", pw, digestparams);
+                                                   false, u, realm, "Digest", pw,
+                                                   digestparams, srv.authenticatorKey);
                                 d.addToCache ();
                             } catch (Exception e) {}
                         }
@@ -2065,7 +2095,8 @@
                             responses,
                             new HttpCallerInfo(url,
                                                http.getProxyHostUsed(),
-                                               http.getProxyPortUsed()),
+                                               http.getProxyPortUsed(),
+                                               authenticator),
                             dontUseNegotiate,
                             disabledTunnelingSchemes
                     );
@@ -2174,7 +2205,8 @@
     private void setPreemptiveProxyAuthentication(MessageHeader requests) throws IOException {
         AuthenticationInfo pauth
             = AuthenticationInfo.getProxyAuth(http.getProxyHostUsed(),
-                                              http.getProxyPortUsed());
+                                              http.getProxyPortUsed(),
+                                              getAuthenticatorKey());
         if (pauth != null && pauth.supportsPreemptiveAuthorization()) {
             String value;
             if (pauth instanceof DigestAuthentication) {
@@ -2228,7 +2260,8 @@
 
             if (realm == null)
                 realm = "";
-            proxyAuthKey = AuthenticationInfo.getProxyAuthKey(host, port, realm, authScheme);
+            proxyAuthKey = AuthenticationInfo.getProxyAuthKey(host, port, realm,
+                                authScheme, getAuthenticatorKey());
             ret = AuthenticationInfo.getProxyAuth(proxyAuthKey);
             if (ret == null) {
                 switch (authScheme) {
@@ -2248,21 +2281,25 @@
                     }
                     PasswordAuthentication a =
                         privilegedRequestPasswordAuthentication(
+                                    authenticator,
                                     host, addr, port, "http",
                                     realm, scheme, url, RequestorType.PROXY);
                     if (a != null) {
-                        ret = new BasicAuthentication(true, host, port, realm, a);
+                        ret = new BasicAuthentication(true, host, port, realm, a,
+                                             getAuthenticatorKey());
                     }
                     break;
                 case DIGEST:
                     a = privilegedRequestPasswordAuthentication(
+                                    authenticator,
                                     host, null, port, url.getProtocol(),
                                     realm, scheme, url, RequestorType.PROXY);
                     if (a != null) {
                         DigestAuthentication.Parameters params =
                             new DigestAuthentication.Parameters();
                         ret = new DigestAuthentication(true, host, port, realm,
-                                                            scheme, a, params);
+                                             scheme, a, params,
+                                             getAuthenticatorKey());
                     }
                     break;
                 case NTLM:
@@ -2288,6 +2325,7 @@
                             logger.finest("Trying Transparent NTLM authentication");
                         } else {
                             a = privilegedRequestPasswordAuthentication(
+                                                authenticator,
                                                 host, null, port, url.getProtocol(),
                                                 "", scheme, url, RequestorType.PROXY);
                         }
@@ -2299,7 +2337,8 @@
                         */
                         if (tryTransparentNTLMProxy ||
                               (!tryTransparentNTLMProxy && a != null)) {
-                            ret = NTLMAuthenticationProxy.proxy.create(true, host, port, a);
+                            ret = NTLMAuthenticationProxy.proxy.create(true, host,
+                                    port, a, getAuthenticatorKey());
                         }
 
                         /* set to false so that we do not try again */
@@ -2330,7 +2369,8 @@
                     URL u = new URL("http", host, port, "/");
                     String a = defaultAuth.authString(u, scheme, realm);
                     if (a != null) {
-                        ret = new BasicAuthentication (true, host, port, realm, a);
+                        ret = new BasicAuthentication (true, host, port, realm, a,
+                                  getAuthenticatorKey());
                         // not in cache by default - cache on success
                     }
                 } catch (java.net.MalformedURLException ignored) {
@@ -2383,7 +2423,8 @@
             domain = p.findValue ("domain");
             if (realm == null)
                 realm = "";
-            serverAuthKey = AuthenticationInfo.getServerAuthKey(url, realm, authScheme);
+            serverAuthKey = AuthenticationInfo.getServerAuthKey(url, realm, authScheme,
+                                               getAuthenticatorKey());
             ret = AuthenticationInfo.getServerAuth(serverAuthKey);
             InetAddress addr = null;
             if (ret == null) {
@@ -2409,19 +2450,24 @@
                 case BASIC:
                     PasswordAuthentication a =
                         privilegedRequestPasswordAuthentication(
+                            authenticator,
                             url.getHost(), addr, port, url.getProtocol(),
                             realm, scheme, url, RequestorType.SERVER);
                     if (a != null) {
-                        ret = new BasicAuthentication(false, url, realm, a);
+                        ret = new BasicAuthentication(false, url, realm, a,
+                                    getAuthenticatorKey());
                     }
                     break;
                 case DIGEST:
                     a = privilegedRequestPasswordAuthentication(
+                            authenticator,
                             url.getHost(), addr, port, url.getProtocol(),
                             realm, scheme, url, RequestorType.SERVER);
                     if (a != null) {
                         digestparams = new DigestAuthentication.Parameters();
-                        ret = new DigestAuthentication(false, url, realm, scheme, a, digestparams);
+                        ret = new DigestAuthentication(false, url, realm, scheme,
+                                    a, digestparams,
+                                    getAuthenticatorKey());
                     }
                     break;
                 case NTLM:
@@ -2452,6 +2498,7 @@
                             logger.finest("Trying Transparent NTLM authentication");
                         } else {
                             a = privilegedRequestPasswordAuthentication(
+                                authenticator,
                                 url.getHost(), addr, port, url.getProtocol(),
                                 "", scheme, url, RequestorType.SERVER);
                         }
@@ -2464,7 +2511,8 @@
                          */
                         if (tryTransparentNTLMServer ||
                               (!tryTransparentNTLMServer && a != null)) {
-                            ret = NTLMAuthenticationProxy.proxy.create(false, url1, a);
+                            ret = NTLMAuthenticationProxy.proxy.create(false,
+                                     url1, a, getAuthenticatorKey());
                         }
 
                         /* set to false so that we do not try again */
@@ -2488,7 +2536,8 @@
                 && defaultAuth.schemeSupported(scheme)) {
                 String a = defaultAuth.authString(url, scheme, realm);
                 if (a != null) {
-                    ret = new BasicAuthentication (false, url, realm, a);
+                    ret = new BasicAuthentication (false, url, realm, a,
+                                    getAuthenticatorKey());
                     // not in cache by default - cache on success
                 }
             }
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,21 +45,22 @@
     static final boolean supported = proxy != null ? true : false;
     static final boolean supportsTransparentAuth = supported ? supportsTransparentAuth() : false;
 
-    private final Constructor<? extends AuthenticationInfo> threeArgCtr;
-    private final Constructor<? extends AuthenticationInfo> fiveArgCtr;
+    private final Constructor<? extends AuthenticationInfo> fourArgCtr;
+    private final Constructor<? extends AuthenticationInfo> sixArgCtr;
 
-    private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> threeArgCtr,
-                                    Constructor<? extends AuthenticationInfo> fiveArgCtr) {
-        this.threeArgCtr = threeArgCtr;
-        this.fiveArgCtr = fiveArgCtr;
+    private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> fourArgCtr,
+                                    Constructor<? extends AuthenticationInfo> sixArgCtr) {
+        this.fourArgCtr = fourArgCtr;
+        this.sixArgCtr = sixArgCtr;
     }
 
 
     AuthenticationInfo create(boolean isProxy,
                               URL url,
-                              PasswordAuthentication pw) {
+                              PasswordAuthentication pw,
+                              String authenticatorKey) {
         try {
-            return threeArgCtr.newInstance(isProxy, url, pw);
+            return fourArgCtr.newInstance(isProxy, url, pw, authenticatorKey);
         } catch (ReflectiveOperationException roe) {
             finest(roe);
         }
@@ -70,9 +71,10 @@
     AuthenticationInfo create(boolean isProxy,
                               String host,
                               int port,
-                              PasswordAuthentication pw) {
+                              PasswordAuthentication pw,
+                              String authenticatorKey) {
         try {
-            return fiveArgCtr.newInstance(isProxy, host, port, pw);
+            return sixArgCtr.newInstance(isProxy, host, port, pw, authenticatorKey);
         } catch (ReflectiveOperationException roe) {
             finest(roe);
         }
@@ -115,21 +117,23 @@
     @SuppressWarnings("unchecked")
     private static NTLMAuthenticationProxy tryLoadNTLMAuthentication() {
         Class<? extends AuthenticationInfo> cl;
-        Constructor<? extends AuthenticationInfo> threeArg, fiveArg;
+        Constructor<? extends AuthenticationInfo> fourArg, sixArg;
         try {
             cl = (Class<? extends AuthenticationInfo>)Class.forName(clazzStr, true, null);
             if (cl != null) {
-                threeArg = cl.getConstructor(boolean.class,
+                fourArg = cl.getConstructor(boolean.class,
                                              URL.class,
-                                             PasswordAuthentication.class);
-                fiveArg = cl.getConstructor(boolean.class,
+                                             PasswordAuthentication.class,
+                                             String.class);
+                sixArg = cl.getConstructor(boolean.class,
                                             String.class,
                                             int.class,
-                                            PasswordAuthentication.class);
+                                            PasswordAuthentication.class,
+                                            String.class);
                 supportsTA = cl.getDeclaredMethod(supportsTAStr);
                 isTrustedSite = cl.getDeclaredMethod(isTrustedSiteStr, java.net.URL.class);
-                return new NTLMAuthenticationProxy(threeArg,
-                                                   fiveArg);
+                return new NTLMAuthenticationProxy(fourArg,
+                                                   sixArg);
             }
         } catch (ClassNotFoundException cnfe) {
             finest(cnfe);
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -68,7 +68,8 @@
         super(RequestorType.PROXY==hci.authType ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
               hci.scheme.equalsIgnoreCase("Negotiate") ? NEGOTIATE : KERBEROS,
               hci.url,
-              "");
+              "",
+              AuthenticatorKeys.getKey(hci.authenticator));
         this.hci = hci;
     }
 
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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
@@ -39,6 +39,7 @@
 import java.net.Proxy;
 import java.security.Principal;
 import java.security.cert.*;
+import java.util.Objects;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
@@ -46,6 +47,7 @@
 
 import javax.net.ssl.*;
 import sun.net.www.http.HttpClient;
+import sun.net.www.protocol.http.AuthenticatorKeys;
 import sun.net.www.protocol.http.HttpURLConnection;
 import sun.security.action.*;
 
@@ -334,8 +336,12 @@
             }
 
             if (ret != null) {
-                if ((ret.proxy != null && ret.proxy.equals(p)) ||
-                    (ret.proxy == null && p == Proxy.NO_PROXY)) {
+                String ak = httpuc == null ? AuthenticatorKeys.DEFAULT
+                     : httpuc.getAuthenticatorKey();
+                boolean compatible = ((ret.proxy != null && ret.proxy.equals(p)) ||
+                    (ret.proxy == null && p == Proxy.NO_PROXY))
+                     && Objects.equals(ret.getAuthenticatorKey(), ak);
+                if (compatible) {
                     synchronized (ret) {
                         ret.cachedHttpClient = true;
                         assert ret.inCache;
@@ -364,6 +370,9 @@
         }
         if (ret == null) {
             ret = new HttpsClient(sf, url, p, connectTimeout);
+            if (httpuc != null) {
+                ret.authenticatorKey = httpuc.getAuthenticatorKey();
+            }
         } else {
             SecurityManager security = System.getSecurityManager();
             if (security != null) {
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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
@@ -39,6 +39,7 @@
 import java.net.Proxy;
 import java.net.ProtocolException;
 import java.io.*;
+import java.net.Authenticator;
 import javax.net.ssl.*;
 import java.security.Permission;
 import java.security.Principal;
@@ -517,4 +518,9 @@
     public void setChunkedStreamingMode (int chunklen) {
         delegate.setChunkedStreamingMode(chunklen);
     }
+
+    @Override
+    public void setAuthenticator(Authenticator auth) {
+        delegate.setAuthenticator(auth);
+    }
 }
--- a/jdk/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, 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
@@ -64,8 +64,9 @@
     // invalid, the parser should flag an error in accordance
     // with its logic.
 
-    private char[] input; // the input signature
-    private int index = 0; // index into the input
+    private String input; // the input signature
+    private int index;    // index into the input
+    private int mark;     // index of mark
     // used to mark end of input
     private static final char EOI = ':';
     private static final boolean DEBUG = false;
@@ -73,6 +74,12 @@
     // private constructor - enforces use of static factory
     private SignatureParser(){}
 
+    // prepares parser for new parsing session
+    private void init(String s) {
+        input = s;
+        mark = index = 0;
+    }
+
     // Utility methods.
 
     // Most parsing routines use the following routines to access the
@@ -80,39 +87,32 @@
     // This makes it easy to adapt the parser to operate on streams
     // of various kinds as well as strings.
 
-    // returns current element of the input and advances the input
-    private char getNext(){
-        assert(index <= input.length);
-        try {
-            return input[index++];
-        } catch (ArrayIndexOutOfBoundsException e) { return EOI;}
-    }
-
     // returns current element of the input
     private char current(){
-        assert(index <= input.length);
-        try {
-            return input[index];
-        } catch (ArrayIndexOutOfBoundsException e) { return EOI;}
+        assert(index <= input.length());
+        return index < input.length() ? input.charAt(index) : EOI;
     }
 
     // advance the input
     private void advance(){
-        assert(index <= input.length);
-        index++;
+        assert(index <= input.length());
+        if (index < input.length()) index++;
+    }
+
+    // mark current position
+    private void mark() {
+        mark = index;
     }
 
     // For debugging, prints current character to the end of the input.
     private String remainder() {
-        return new String(input, index, input.length-index);
+        return input.substring(index);
     }
 
-    // Match c against a "set" of characters
-    private boolean matches(char c, char... set) {
-        for (char e : set) {
-            if (c == e) return true;
-        }
-        return false;
+    // returns a substring of input from mark (inclusive)
+    // to current position (exclusive)
+    private String markToCurrent() {
+        return input.substring(mark, index);
     }
 
     // Error handling routine. Encapsulates error handling.
@@ -152,7 +152,7 @@
      */
     public ClassSignature parseClassSig(String s) {
         if (DEBUG) System.out.println("Parsing class sig:" + s);
-        input = s.toCharArray();
+        init(s);
         return parseClassSignature();
     }
 
@@ -167,7 +167,7 @@
      */
     public MethodTypeSignature parseMethodSig(String s) {
         if (DEBUG) System.out.println("Parsing method sig:" + s);
-        input = s.toCharArray();
+        init(s);
         return parseMethodTypeSignature();
     }
 
@@ -184,13 +184,13 @@
      */
     public TypeSignature parseTypeSig(String s) {
         if (DEBUG) System.out.println("Parsing type sig:" + s);
-        input = s.toCharArray();
+        init(s);
         return parseTypeSignature();
     }
 
     // Parsing routines.
     // As a rule, the parsing routines access the input using the
-    // utilities current(), getNext() and/or advance().
+    // utilities current() and advance().
     // The convention is that when a parsing routine is invoked
     // it expects the current input to be the first character it should parse
     // and when it completes parsing, it leaves the input at the first
@@ -251,28 +251,22 @@
         return FormalTypeParameter.make(id, bs);
     }
 
-    private String parseIdentifier(){
-        StringBuilder result = new StringBuilder();
-        while (!Character.isWhitespace(current())) {
-            char c = current();
-            switch(c) {
-            case ';':
-            case '.':
-            case '/':
-            case '[':
-            case ':':
-            case '>':
-            case '<':
-                return result.toString();
-            default:{
-                result.append(c);
-                advance();
-            }
+    private String parseIdentifier() {
+        mark();
+        skipIdentifier();
+        return markToCurrent();
+    }
 
-            }
+    private void skipIdentifier() {
+        char c = current();
+        while (c != ';' && c != '.' && c != '/' &&
+               c != '[' && c != ':' && c != '>' &&
+               c != '<' && !Character.isWhitespace(c)) {
+            advance();
+            c = current();
         }
-        return result.toString();
     }
+
     /**
      * FieldTypeSignature:
      *     ClassTypeSignature
@@ -325,18 +319,13 @@
         // Parse both any optional leading PackageSpecifier as well as
         // the following SimpleClassTypeSignature.
 
-        String id = parseIdentifier();
-
-        if (current() == '/') { // package name
-            StringBuilder idBuild = new StringBuilder(id);
-
-            while(current() == '/') {
-                advance();
-                idBuild.append(".");
-                idBuild.append(parseIdentifier());
-            }
-            id = idBuild.toString();
+        mark();
+        skipIdentifier();
+        while (current() == '/') {
+            advance();
+            skipIdentifier();
         }
+        String id = markToCurrent().replace('/', '.');
 
         switch (current()) {
         case ';':
@@ -379,11 +368,6 @@
         }
     }
 
-    private TypeArgument[] parseTypeArgumentsOpt() {
-        if (current() == '<') {return parseTypeArguments();}
-        else {return new TypeArgument[0];}
-    }
-
     /**
      * TypeArguments:
      *     "<" TypeArgument+ ">"
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Wed Jul 05 22:32:06 2017 +0200
@@ -324,15 +324,17 @@
 
         PublicKey currPubKey = cert.getPublicKey();
 
-        // Check against DisabledAlgorithmConstraints certpath constraints.
-        // permits() will throw exception on failure.
-        certPathDefaultConstraints.permits(primitives,
+        if (constraints instanceof DisabledAlgorithmConstraints) {
+            // Check against DisabledAlgorithmConstraints certpath constraints.
+            // permits() will throw exception on failure.
+            ((DisabledAlgorithmConstraints)constraints).permits(primitives,
                 new CertConstraintParameters((X509Certificate)cert,
                         trustedMatch, pkixdate, jarTimestamp));
-        // If there is no previous key, set one and exit
-        if (prevPubKey == null) {
-            prevPubKey = currPubKey;
-            return;
+            // If there is no previous key, set one and exit
+            if (prevPubKey == null) {
+                prevPubKey = currPubKey;
+                return;
+            }
         }
 
         X509CertImpl x509Cert;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProvider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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 sun.security.util;
+
+public interface AuthResourcesProvider extends java.util.spi.ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProviderImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 sun.security.util;
+
+import java.util.spi.AbstractResourceBundleProvider;
+
+public final class AuthResourcesProviderImpl extends AbstractResourceBundleProvider
+       implements AuthResourcesProvider {
+    public AuthResourcesProviderImpl() {
+        super("java.class");
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/text/spi/JavaTimeDateTimePatternProvider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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 sun.text.spi;
+
+import java.util.Locale;
+import java.util.spi.LocaleServiceProvider;
+
+/**
+ * Service Provider Interface for retrieving DateTime patterns from
+ * specified Locale provider for java.time.
+ */
+
+public abstract class JavaTimeDateTimePatternProvider extends LocaleServiceProvider {
+
+    protected JavaTimeDateTimePatternProvider() {
+    }
+
+    /**
+     * Gets the formatting pattern for a timeStyle
+     * dateStyle, calendarType and locale.
+     * Concrete implementation of this method will retrieve
+     * a java.time specific dateTime Pattern from selected Locale Provider.
+     *
+     * @param timeStyle an {@code int} value representing FormatStyle constant, -1
+     * for date-only pattern
+     * @param dateStyle an {@code int} value,representing FormatStyle constant, -1
+     * for time-only pattern
+     * @param locale {@code locale}, non-null
+     * @param calType a {@code String},non-null representing CalendarType such as "japanese",
+     * "iso8601"
+     * @return  formatting pattern {@code String}
+     * @see java.time.format.DateTimeFormatterBuilder#convertStyle(java.time.format.FormatStyle)
+     * @since 9
+     */
+    public abstract String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale);
+}
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -45,6 +45,7 @@
 import java.util.spi.LocaleNameProvider;
 import java.util.spi.LocaleServiceProvider;
 import java.util.spi.TimeZoneNameProvider;
+import sun.text.spi.JavaTimeDateTimePatternProvider;
 import sun.util.spi.CalendarProvider;
 
 /**
@@ -156,6 +157,11 @@
         return null;
     }
 
+    @Override
+    public JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
+        return getLocaleServiceProvider(JavaTimeDateTimePatternProvider.class);
+    }
+
     private static Locale[] availableLocales = null;
 
     @Override
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -50,6 +50,7 @@
 import java.util.spi.LocaleNameProvider;
 import java.util.spi.LocaleServiceProvider;
 import java.util.spi.TimeZoneNameProvider;
+import sun.text.spi.JavaTimeDateTimePatternProvider;
 import sun.util.resources.LocaleData;
 import sun.util.spi.CalendarProvider;
 
@@ -109,6 +110,8 @@
             return (P) getCalendarNameProvider();
         case "CalendarProvider":
             return (P) getCalendarProvider();
+        case "JavaTimeDateTimePatternProvider":
+            return (P) getJavaTimeDateTimePatternProvider();
         default:
             throw new InternalError("should not come down here");
         }
@@ -128,6 +131,7 @@
     private volatile CalendarNameProvider calendarNameProvider;
 
     private volatile CalendarProvider calendarProvider;
+    private volatile JavaTimeDateTimePatternProvider javaTimeDateTimePatternProvider;
 
     /*
      * Getter methods for java.text.spi.* providers
@@ -354,6 +358,27 @@
         return calendarProvider;
     }
 
+    /**
+     * Getter methods for sun.text.spi.JavaTimeDateTimePatternProvider provider
+     */
+    @Override
+    public JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
+        if (javaTimeDateTimePatternProvider == null) {
+            JavaTimeDateTimePatternProvider provider = AccessController.doPrivileged(
+                    (PrivilegedAction<JavaTimeDateTimePatternProvider>) ()
+                    -> new JavaTimeDateTimePatternImpl(
+                            getAdapterType(),
+                            getLanguageTagSet("FormatData")));
+
+            synchronized (this) {
+                if (javaTimeDateTimePatternProvider == null) {
+                    javaTimeDateTimePatternProvider = provider;
+                }
+            }
+        }
+        return javaTimeDateTimePatternProvider;
+    }
+
     @Override
     public LocaleResources getLocaleResources(Locale locale) {
         LocaleResources lr = localeResourcesMap.get(locale);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/JavaTimeDateTimePatternImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,76 @@
+/*
+ * 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 sun.util.locale.provider;
+
+import java.util.Locale;
+import java.util.Set;
+import sun.text.spi.JavaTimeDateTimePatternProvider;
+
+/**
+ * Concrete implementation of the {@link sun.text.spi.JavaTimeDateTimePatternProvider
+ * } class for the JRE LocaleProviderAdapter.
+ *
+ */
+public class JavaTimeDateTimePatternImpl extends JavaTimeDateTimePatternProvider implements AvailableLanguageTags {
+
+    private final LocaleProviderAdapter.Type type;
+    private final Set<String> langtags;
+
+    public JavaTimeDateTimePatternImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
+        this.type = type;
+        this.langtags = langtags;
+    }
+
+    /**
+     * Returns an array of all locales for which this locale service provider
+     * can provide localized objects or names.
+     *
+     * @return An array of all locales for which this locale service provider
+     * can provide localized objects or names.
+     */
+    @Override
+    public Locale[] getAvailableLocales() {
+        return LocaleProviderAdapter.toLocaleArray(langtags);
+    }
+
+    @Override
+    public boolean isSupportedLocale(Locale locale) {
+        return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags);
+    }
+
+    @Override
+    public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
+        LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale);
+        String pattern = lr.getJavaTimeDateTimePattern(
+                timeStyle, dateStyle, calType);
+        return pattern;
+
+    }
+
+    @Override
+    public Set<String> getAvailableLanguageTags() {
+        return langtags;
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Wed Jul 05 22:32:06 2017 +0200
@@ -47,6 +47,7 @@
 import java.util.spi.LocaleServiceProvider;
 import java.util.spi.TimeZoneNameProvider;
 import sun.security.action.GetPropertyAction;
+import sun.text.spi.JavaTimeDateTimePatternProvider;
 import sun.util.spi.CalendarProvider;
 
 /**
@@ -428,6 +429,14 @@
      */
     public abstract CalendarProvider getCalendarProvider();
 
+    /**
+     * Returns a JavaTimeDateTimePatternProvider for this LocaleProviderAdapter,
+     * or null if no JavaTimeDateTimePatternProvider is available.
+     *
+     * @return a JavaTimeDateTimePatternProvider
+     */
+    public abstract JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider();
+
     public abstract LocaleResources getLocaleResources(Locale locale);
 
     public abstract Locale[] getAvailableLocales();
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-/*
- * Copyright (c) 2015, 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 sun.util.locale.provider;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Module;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.PropertyResourceBundle;
-import java.util.ResourceBundle;
-
-/**
- * ResourceBundleProviderSupport provides convenience methods for loading
- * resource bundles.
- */
-public class ResourceBundleProviderSupport {
-    /**
-     * Loads a {@code ResourceBundle} of the given {@code bundleName} local to
-     * the given {@code module}.
-     *
-     * @apiNote
-     * {@link Class#forName(Module, String)} does a stack-based permission check.
-     * Caller of this method is responsible for doing an appropriate permission
-     * on behalf of the caller before calling this method.
-     *
-     * @param module     the module from which the {@code ResourceBundle} is loaded
-     * @param bundleName the bundle name for the {@code ResourceBundle} class,
-     *                   such as "com.example.app.MyResources_fr"
-     * @return the {@code ResourceBundle}, or null if no {@code ResourceBundle} is found
-     * @throws SecurityException
-     *         if a security manager exists, it denies loading the class given by
-     *         {@code bundleName} from the given {@code module}.
-     *         If the given module is "java.base", this method will not do security check.
-     * @throws NullPointerException
-     *         if {@code module} or {@code bundleName) is null
-     * @see Class#forName(Module, String)
-     */
-    public static ResourceBundle loadResourceBundle(Module module, String bundleName)
-    {
-        Class<?> c = Class.forName(module, bundleName);
-        if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
-            try {
-                @SuppressWarnings("unchecked")
-                Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
-                Constructor<ResourceBundle> ctor = bundleClass.getConstructor();
-                if (!Modifier.isPublic(ctor.getModifiers())) {
-                    return null;
-                }
-                // java.base may not be able to read the bundleClass's module.
-                PrivilegedAction<Void> pa1 = () -> { ctor.setAccessible(true); return null; };
-                AccessController.doPrivileged(pa1);
-                try {
-                    return ctor.newInstance((Object[]) null);
-                } catch (InvocationTargetException e) {
-                    uncheckedThrow(e);
-                } catch (InstantiationException | IllegalAccessException e) {
-                    throw new InternalError(e);
-                }
-            } catch (NoSuchMethodException e) {
-            }
-        }
-        return null;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
-       if (t != null)
-            throw (T)t;
-       else
-            throw new Error("Unknown Exception");
-    }
-
-    /**
-     * Loads properties of the given {@code bundleName} local to the given
-     * {@code module} and returns a {@code ResourceBundle} produced from the
-     * loaded properties.
-     *
-     * @apiNote This method is intended for internal use.  Need to refactor.
-     *
-     * @param module     the module from which the properties are loaded
-     * @param bundleName the bundle name of the properties,
-     *                   such as "com.example.app.MyResources_de"
-     * @return the {@code ResourceBundle} produced from the loaded properties,
-     *         or null if no properties are found
-     * @see PropertyResourceBundle
-     */
-    public static ResourceBundle loadPropertyResourceBundle(Module module, String bundleName)
-            throws IOException
-    {
-        String resourceName = toResourceName(bundleName, "properties");
-        if (resourceName == null) {
-            return null;
-        }
-
-        PrivilegedAction<InputStream> pa = () -> {
-            try {
-                return module.getResourceAsStream(resourceName);
-            } catch (IOException e) {
-                throw new UncheckedIOException(e);
-            }
-        };
-        try (InputStream stream = AccessController.doPrivileged(pa)) {
-            if (stream != null) {
-                return new PropertyResourceBundle(stream);
-            } else {
-                return null;
-            }
-        } catch (UncheckedIOException e) {
-            throw e.getCause();
-        }
-    }
-
-    private static String toResourceName(String bundleName, String suffix) {
-        if (bundleName.contains("://")) {
-            return null;
-        }
-        StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
-        sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
-        return sb.toString();
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java	Wed Jul 05 22:32:06 2017 +0200
@@ -58,8 +58,6 @@
 import java.util.spi.ResourceBundleProvider;
 import jdk.internal.misc.JavaUtilResourceBundleAccess;
 import jdk.internal.misc.SharedSecrets;
-import sun.util.locale.provider.ResourceBundleProviderSupport;
-
 
 /**
  */
@@ -203,9 +201,13 @@
                 bundle = loadBundleFromProviders(baseName, targetLocale, providers, cacheKey);
             } else {
                 try {
-                    bundle = ResourceBundleProviderSupport
-                                 .loadResourceBundle(Bundles.class.getModule(),
-                                      strategy.toBundleName(baseName, targetLocale));
+                    String bundleName = strategy.toBundleName(baseName, targetLocale);
+                    Class<?> c = Class.forName(Bundles.class.getModule(), bundleName);
+                    if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
+                        @SuppressWarnings("unchecked")
+                        Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
+                        bundle = bundleAccess.newResourceBundle(bundleClass);
+                    }
                 } catch (Exception e) {
                     cacheKey.setCause(e);
                 }
--- a/jdk/src/java.base/share/conf/security/java.security	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/conf/security/java.security	Wed Jul 05 22:32:06 2017 +0200
@@ -849,35 +849,35 @@
 #       FFFFFFFF FFFFFFFF, 2}
 
 # Cryptographic Jurisdiction Policy defaults
-# 
+#
 # Due to the import control restrictions of some countries, the default
 # JCE policy files allow for strong but "limited" cryptographic key
 # lengths to be used.  If your country's cryptographic regulations allow,
 # the "unlimited" strength policy files can be used instead, which contain
 # no restrictions on cryptographic strengths.
-# 
+#
 # If your country has restrictions that don't fit either "limited" or
 # "unlimited", an appropriate set of policy files should be created and
 # configured before using this distribution.  The jurisdiction policy file
 # configuration must reflect the cryptographic restrictions appropriate
 # for your country.
-# 
+#
 # YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY
 # TO DETERMINE THE EXACT REQUIREMENTS.
-# 
+#
 # The policy files are flat text files organized into subdirectories of
 # <java-home>/conf/security/policy.  Each directory contains a complete
 # set of policy files.
 #
 # The "crypto.policy" Security property controls the directory selection,
 # and thus the effective cryptographic policy.
-# 
-# The default set of directories is:  
-# 
-#     limited | unlimited 
-# 
+#
+# The default set of directories is:
+#
+#     limited | unlimited
+#
 # however other directories can be created and configured.
-# 
+#
 # Within a directory, the effective policy is the combined minimum
 # permissions of the grant statements in the file(s) with the filename
 # pattern "default_*.policy".  At least one grant is required.  For
@@ -891,11 +891,15 @@
 # "exempt_*.policy".  Exemption grants are optional.
 #
 #     limited   =  grants exemption permissions, by which the
-#                  effective policy can be circumvented. 
+#                  effective policy can be circumvented.
 #                  e.g.  KeyRecovery/Escrow/Weakening.
-# 
+#
 # Please see the JCA documentation for additional information on these
 # files and formats.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
 crypto.policy=crypto.policydir-tbd
 
 #
@@ -951,7 +955,8 @@
 #
 # 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.
+# 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
@@ -961,20 +966,24 @@
 #
 # 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.
+# 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 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 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 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.
 #
--- a/jdk/src/java.base/share/conf/security/policy/README.txt	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/conf/security/policy/README.txt	Wed Jul 05 22:32:06 2017 +0200
@@ -10,11 +10,10 @@
 configured via the jurisdiction policy files contained within these
 directories.
 
-Due to import control restrictions of some countries, the default
-JCE policy files bundled in this Java Runtime Environment allow
-for strong but "limited" cryptographic strengths.  For convenience,
-this build also contains the "unlimited strength" policy files which
-contain no restrictions on cryptographic strengths, but they must be
+The default JCE policy files bundled in this Java Runtime Environment
+allow for "unlimited" cryptographic strengths.  For convenience,
+this build also contains the historic "limited" strength policy files
+which contain restrictions on cryptographic strengths, but they must be
 specifically activated by updating the "crypto.policy" Security property
 (e.g. <java-home>/conf/security/java.security) to point to the appropriate
 directory.
--- a/jdk/src/java.base/share/native/include/jni.h	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/native/include/jni.h	Wed Jul 05 22:32:06 2017 +0200
@@ -770,12 +770,6 @@
 
     jobject (JNICALL *GetModule)
        (JNIEnv* env, jclass clazz);
-
-    void (JNICALL *AddModuleReads)
-        (JNIEnv* env, jobject m1, jobject m2);
-
-    jboolean (JNICALL *CanReadModule)
-        (JNIEnv* env, jobject m1, jobject m2);
 };
 
 /*
@@ -1874,14 +1868,6 @@
         return functions->GetModule(this, clazz);
     }
 
-    void AddModuleReads(jobject m1, jobject m2) {
-        functions->AddModuleReads(this, m1, m2);
-    }
-
-    jboolean CanReadModule(jobject m1, jobject m2) {
-        return functions->CanReadModule(this, m1, m2);
-    }
-
 #endif /* __cplusplus */
 };
 
--- a/jdk/src/java.base/share/native/include/jvm.h	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/native/include/jvm.h	Wed Jul 05 22:32:06 2017 +0200
@@ -402,8 +402,8 @@
  */
 
 JNIEXPORT void JNICALL
-JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location,
-                 jobjectArray packages);
+JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version,
+                 jstring location, jobjectArray packages);
 
 JNIEXPORT void JNICALL
 JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module);
@@ -411,9 +411,6 @@
 JNIEXPORT void JNICALL
 JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject to_module);
 
-JNIEXPORT jboolean JNICALL
-JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module);
-
 JNIEXPORT void JNICALL
 JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module);
 
@@ -423,9 +420,6 @@
 JNIEXPORT void JNICALL
 JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package);
 
-JNIEXPORT jboolean JNICALL
-JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module);
-
 JNIEXPORT void JNICALL
 JVM_AddModulePackage(JNIEnv* env,  jobject module, jstring package);
 
--- a/jdk/src/java.base/share/native/libjava/Module.c	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/native/libjava/Module.c	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
 
 JNIEXPORT void JNICALL
 Java_java_lang_reflect_Module_defineModule0(JNIEnv *env, jclass cls, jobject module,
-                                            jstring version, jstring location,
-                                            jobjectArray packages)
+                                            jboolean is_open, jstring version,
+                                            jstring location, jobjectArray packages)
 {
-    JVM_DefineModule(env, module, version, location, packages);
+    JVM_DefineModule(env, module, is_open, version, location, packages);
 }
 
 JNIEXPORT void JNICALL
--- a/jdk/src/java.base/share/native/libjli/java.c	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/native/libjli/java.c	Wed Jul 05 22:32:06 2017 +0200
@@ -61,12 +61,13 @@
  * interfaces.
  */
 
-/* we always print to stderr */
-#define USE_STDERR JNI_TRUE
+#define USE_STDERR JNI_TRUE     /* we usually print to stderr */
+#define USE_STDOUT JNI_FALSE
 
 static jboolean printVersion = JNI_FALSE; /* print and exit */
 static jboolean showVersion = JNI_FALSE;  /* print but continue */
 static jboolean printUsage = JNI_FALSE;   /* print and exit*/
+static jboolean printTo = USE_STDERR;     /* where to print version/usage */
 static jboolean printXUsage = JNI_FALSE;  /* print and exit*/
 static jboolean dryRun = JNI_FALSE;       /* initialize VM and exit */
 static char     *showSettings = NULL;     /* print but continue */
@@ -567,6 +568,7 @@
            JLI_StrCmp(name, "--add-modules") == 0 ||
            JLI_StrCmp(name, "--limit-modules") == 0 ||
            JLI_StrCmp(name, "--add-exports") == 0 ||
+           JLI_StrCmp(name, "--add-opens") == 0 ||
            JLI_StrCmp(name, "--add-reads") == 0 ||
            JLI_StrCmp(name, "--patch-module") == 0;
 }
@@ -758,12 +760,15 @@
 
             if (*arg != '-'
                     || JLI_StrCmp(arg, "-version") == 0
+                    || JLI_StrCmp(arg, "--version") == 0
                     || JLI_StrCmp(arg, "-fullversion") == 0
+                    || JLI_StrCmp(arg, "--full-version") == 0
                     || JLI_StrCmp(arg, "-help") == 0
                     || JLI_StrCmp(arg, "--help") == 0
                     || JLI_StrCmp(arg, "-?") == 0
                     || JLI_StrCmp(arg, "-jar") == 0
-                    || JLI_StrCmp(arg, "-X") == 0) {
+                    || JLI_StrCmp(arg, "-X") == 0
+                    || JLI_StrCmp(arg, "--help-extra") == 0) {
                 return;
             }
         }
@@ -1288,6 +1293,7 @@
             } else if (JLI_StrCmp(arg, "--add-modules") == 0 ||
                        JLI_StrCmp(arg, "--limit-modules") == 0 ||
                        JLI_StrCmp(arg, "--add-exports") == 0 ||
+                       JLI_StrCmp(arg, "--add-opens") == 0 ||
                        JLI_StrCmp(arg, "--add-reads") == 0 ||
                        JLI_StrCmp(arg, "--patch-module") == 0) {
                 REPORT_ERROR (has_arg, ARG_ERROR6, arg);
@@ -1295,22 +1301,36 @@
 /*
  * The following cases will cause the argument parsing to stop
  */
-        } else if (JLI_StrCmp(arg, "--help") == 0 ||
-                   JLI_StrCmp(arg, "-help") == 0 ||
+        } else if (JLI_StrCmp(arg, "-help") == 0 ||
                    JLI_StrCmp(arg, "-h") == 0 ||
                    JLI_StrCmp(arg, "-?") == 0) {
             printUsage = JNI_TRUE;
             return JNI_TRUE;
+        } else if (JLI_StrCmp(arg, "--help") == 0) {
+            printUsage = JNI_TRUE;
+            printTo = USE_STDOUT;
+            return JNI_TRUE;
         } else if (JLI_StrCmp(arg, "-version") == 0) {
             printVersion = JNI_TRUE;
             return JNI_TRUE;
+        } else if (JLI_StrCmp(arg, "--version") == 0) {
+            printVersion = JNI_TRUE;
+            printTo = USE_STDOUT;
+            return JNI_TRUE;
         } else if (JLI_StrCmp(arg, "-showversion") == 0) {
             showVersion = JNI_TRUE;
+        } else if (JLI_StrCmp(arg, "--show-version") == 0) {
+            showVersion = JNI_TRUE;
+            printTo = USE_STDOUT;
         } else if (JLI_StrCmp(arg, "--dry-run") == 0) {
             dryRun = JNI_TRUE;
         } else if (JLI_StrCmp(arg, "-X") == 0) {
             printXUsage = JNI_TRUE;
             return JNI_TRUE;
+        } else if (JLI_StrCmp(arg, "--help-extra") == 0) {
+            printXUsage = JNI_TRUE;
+            printTo = USE_STDOUT;
+            return JNI_TRUE;
 /*
  * The following case checks for -XshowSettings OR -XshowSetting:SUBOPT.
  * In the latter case, any SUBOPT value not recognized will default to "all"
@@ -1330,6 +1350,9 @@
         } else if (JLI_StrCmp(arg, "-fullversion") == 0) {
             JLI_ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion());
             return JNI_FALSE;
+        } else if (JLI_StrCmp(arg, "--full-version") == 0) {
+            JLI_ShowMessage("%s %s", _launcher_name, GetFullVersion());
+            return JNI_FALSE;
         } else if (JLI_StrCmp(arg, "-verbosegc") == 0) {
             AddOption("-verbose:gc", NULL);
         } else if (JLI_StrCmp(arg, "-t") == 0) {
@@ -1752,11 +1775,11 @@
     NULL_CHECK(print = (*env)->GetStaticMethodID(env,
                                                  ver,
                                                  (extraLF == JNI_TRUE) ? "println" : "print",
-                                                 "()V"
+                                                 "(Z)V"
                                                  )
               );
 
-    (*env)->CallStaticVoidMethod(env, ver, print);
+    (*env)->CallStaticVoidMethod(env, ver, print, printTo);
 }
 
 /*
@@ -1794,7 +1817,7 @@
             "listModules", "(ZLjava/lang/String;)V"));
     NULL_CHECK(joptString = (*env)->NewStringUTF(env, optString));
     (*env)->CallStaticVoidMethod(env, cls, listModulesID,
-                                 USE_STDERR,
+                                 USE_STDOUT,
                                  joptString);
 }
 
@@ -1812,7 +1835,7 @@
   if (doXUsage) {
     NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls,
                                         "printXUsageMessage", "(Z)V"));
-    (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, USE_STDERR);
+    (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, printTo);
   } else {
     NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls,
                                         "initHelpMessage", "(Ljava/lang/String;)V"));
@@ -1853,7 +1876,7 @@
     }
 
     /* Complete the usage message and print to stderr*/
-    (*env)->CallStaticVoidMethod(env, cls, printHelp, USE_STDERR);
+    (*env)->CallStaticVoidMethod(env, cls, printHelp, printTo);
   }
   return;
 }
@@ -2255,3 +2278,16 @@
     fprintf(stderr, "\n");
     va_end(vl);
 }
+
+/*
+ * A utility procedure to always print to stdout
+ */
+void
+JLI_ShowMessage(const char* fmt, ...)
+{
+    va_list vl;
+    va_start(vl, fmt);
+    vfprintf(stdout, fmt, vl);
+    fprintf(stdout, "\n");
+    va_end(vl);
+}
--- a/jdk/src/java.base/share/native/libjli/java.h	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/share/native/libjli/java.h	Wed Jul 05 22:32:06 2017 +0200
@@ -140,6 +140,9 @@
 /* Reports an error message only to stderr. */
 void JLI_ReportMessage(const char * message, ...);
 
+/* Reports a message only to stdout. */
+void JLI_ShowMessage(const char * message, ...);
+
 /*
  * Reports an exception which terminates the vm to stderr or a window
  * as appropriate.
--- a/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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 @@
 import java.net.URL;
 import java.security.GeneralSecurityException;
 import java.util.Base64;
+import java.util.Objects;
 
 import sun.net.www.HeaderParser;
 import sun.net.www.protocol.http.AuthenticationInfo;
@@ -116,11 +117,13 @@
      * If this notation is not used, then the domain will be taken
      * from a system property: "http.auth.ntlm.domain".
      */
-    public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
+    public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw,
+                              String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
                 AuthScheme.NTLM,
                 url,
-                "");
+                "",
+                Objects.requireNonNull(authenticatorKey));
         init (pw);
     }
 
@@ -157,12 +160,14 @@
     * Constructor used for proxy entries
     */
     public NTLMAuthentication(boolean isProxy, String host, int port,
-                                PasswordAuthentication pw) {
+                              PasswordAuthentication pw,
+                              String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
                 AuthScheme.NTLM,
                 host,
                 port,
-                "");
+                "",
+                Objects.requireNonNull(authenticatorKey));
         init (pw);
     }
 
@@ -242,4 +247,3 @@
         return result;
     }
 }
-
--- a/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -30,6 +30,7 @@
 import java.net.PasswordAuthentication;
 import java.net.UnknownHostException;
 import java.net.URL;
+import java.util.Objects;
 import sun.net.www.HeaderParser;
 import sun.net.www.protocol.http.AuthenticationInfo;
 import sun.net.www.protocol.http.AuthScheme;
@@ -88,11 +89,13 @@
      * If this notation is not used, then the domain will be taken
      * from a system property: "http.auth.ntlm.domain".
      */
-    public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
+    public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw,
+                              String authenticatorKey) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
               AuthScheme.NTLM,
               url,
-              "");
+              "",
+              Objects.requireNonNull(authenticatorKey));
         init (pw);
     }
 
@@ -122,12 +125,14 @@
     * Constructor used for proxy entries
     */
     public NTLMAuthentication(boolean isProxy, String host, int port,
-                                PasswordAuthentication pw) {
+                              PasswordAuthentication pw,
+                              String authenticatorKey) {
         super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION,
               AuthScheme.NTLM,
               host,
               port,
-              "");
+              "",
+              Objects.requireNonNull(authenticatorKey));
         init (pw);
     }
 
--- a/jdk/src/java.base/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.base/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -52,6 +52,7 @@
 import java.util.spi.CalendarNameProvider;
 import java.util.spi.CurrencyNameProvider;
 import java.util.spi.LocaleNameProvider;
+import sun.text.spi.JavaTimeDateTimePatternProvider;
 import sun.util.spi.CalendarProvider;
 
 /**
@@ -525,6 +526,167 @@
         };
     }
 
+    public static JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
+        return new JavaTimeDateTimePatternProvider() {
+            @Override
+            public Locale[] getAvailableLocales() {
+                return getSupportedCalendarLocales();
+            }
+
+            @Override
+            public boolean isSupportedLocale(Locale locale) {
+                return isSupportedCalendarLocale(locale);
+            }
+
+            @Override
+            public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
+                AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
+                String pattern = new StringBuilder(patterns.get(dateStyle / 2))
+                        .append(" ")
+                        .append(patterns.get(timeStyle / 2 + 2))
+                        .toString();
+                return toJavaTimeDateTimePattern(calType, pattern);
+
+            }
+
+            private AtomicReferenceArray<String> getDateTimePatterns(Locale locale) {
+                AtomicReferenceArray<String> patterns;
+                SoftReference<AtomicReferenceArray<String>> ref = dateFormatCache.get(locale);
+
+                if (ref == null || (patterns = ref.get()) == null) {
+                    String langtag = removeExtensions(locale).toLanguageTag();
+                    patterns = new AtomicReferenceArray<>(4);
+                    patterns.compareAndSet(0, null, convertDateTimePattern(
+                            getDateTimePattern(DateFormat.LONG, -1, langtag)));
+                    patterns.compareAndSet(1, null, convertDateTimePattern(
+                            getDateTimePattern(DateFormat.SHORT, -1, langtag)));
+                    patterns.compareAndSet(2, null, convertDateTimePattern(
+                            getDateTimePattern(-1, DateFormat.LONG, langtag)));
+                    patterns.compareAndSet(3, null, convertDateTimePattern(
+                            getDateTimePattern(-1, DateFormat.SHORT, langtag)));
+                    ref = new SoftReference<>(patterns);
+                    dateFormatCache.put(locale, ref);
+                }
+                return patterns;
+            }
+            /**
+             * This method will convert JRE Date/time Pattern String to JSR310
+             * type Date/Time Pattern
+             */
+            private String toJavaTimeDateTimePattern(String calendarType, String jrePattern) {
+                int length = jrePattern.length();
+                StringBuilder sb = new StringBuilder(length);
+                boolean inQuote = false;
+                int count = 0;
+                char lastLetter = 0;
+                for (int i = 0; i < length; i++) {
+                    char c = jrePattern.charAt(i);
+                    if (c == '\'') {
+                        // '' is treated as a single quote regardless of being
+                        // in a quoted section.
+                        if ((i + 1) < length) {
+                            char nextc = jrePattern.charAt(i + 1);
+                            if (nextc == '\'') {
+                                i++;
+                                if (count != 0) {
+                                    convert(calendarType, lastLetter, count, sb);
+                                    lastLetter = 0;
+                                    count = 0;
+                                }
+                                sb.append("''");
+                                continue;
+                            }
+                        }
+                        if (!inQuote) {
+                            if (count != 0) {
+                                convert(calendarType, lastLetter, count, sb);
+                                lastLetter = 0;
+                                count = 0;
+                            }
+                            inQuote = true;
+                        } else {
+                            inQuote = false;
+                        }
+                        sb.append(c);
+                        continue;
+                    }
+                    if (inQuote) {
+                        sb.append(c);
+                        continue;
+                    }
+                    if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
+                        if (count != 0) {
+                            convert(calendarType, lastLetter, count, sb);
+                            lastLetter = 0;
+                            count = 0;
+                        }
+                        sb.append(c);
+                        continue;
+                    }
+                    if (lastLetter == 0 || lastLetter == c) {
+                        lastLetter = c;
+                        count++;
+                        continue;
+                    }
+                    convert(calendarType, lastLetter, count, sb);
+                    lastLetter = c;
+                    count = 1;
+                }
+                if (inQuote) {
+                    // should not come here.
+                    // returning null so that FALLBACK provider will kick in.
+                    return null;
+                }
+                if (count != 0) {
+                    convert(calendarType, lastLetter, count, sb);
+                }
+                return sb.toString();
+            }
+
+            private void convert(String calendarType, char letter, int count, StringBuilder sb) {
+                switch (letter) {
+                    case 'G':
+                        if (calendarType.equals("japanese")) {
+                            if (count >= 4) {
+                                count = 1;
+                            } else {
+                                count = 5;
+                            }
+                        } else if (!calendarType.equals("iso8601")) {
+                            // Adjust the number of 'G's
+                            // Gregorian calendar is iso8601 for java.time
+                            if (count >= 4) {
+                                // JRE full -> JavaTime full
+                                count = 4;
+                            } else {
+                                // JRE short -> JavaTime short
+                                count = 1;
+                            }
+                        }
+                        break;
+                    case 'y':
+                        if (calendarType.equals("japanese") && count >= 4) {
+                            // JRE specific "gan-nen" support
+                            count = 1;
+                        }
+                        break;
+                    default:
+                        // JSR 310 and CLDR define 5-letter patterns for narrow text.
+                        if (count > 4) {
+                            count = 4;
+                        }
+                        break;
+                }
+                appendN(letter, count, sb);
+            }
+
+            private void appendN(char c, int n, StringBuilder sb) {
+                for (int i = 0; i < n; i++) {
+                    sb.append(c);
+                }
+            }
+        };
+    }
 
     private static String convertDateTimePattern(String winPattern) {
         String ret = winPattern.replaceAll("dddd", "EEEE");
--- a/jdk/src/java.compact1/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.compact1/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,7 @@
  * Aggregates {@code java.base}, {@code java.logging}, and {@code java.scripting}.
  */
 module java.compact1 {
-    requires public java.logging;
-    requires public java.scripting;
+    requires transitive java.logging;
+    requires transitive java.scripting;
 }
 
--- a/jdk/src/java.compact2/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.compact2/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,9 +27,9 @@
  * Supplements {@code java.compact1} with JDBC, JAXP, and RMI.
  */
 module java.compact2 {
-    requires public java.compact1;
-    requires public java.rmi;
-    requires public java.sql;
-    requires public java.xml;
+    requires transitive java.compact1;
+    requires transitive java.rmi;
+    requires transitive java.sql;
+    requires transitive java.xml;
 }
 
--- a/jdk/src/java.compact3/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.compact3/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,15 +28,15 @@
  * Instrumentation, Preferences, Security, and XML cryptography APIs.
  */
 module java.compact3 {
-    requires public java.compact2;
-    requires public java.compiler;
-    requires public java.instrument;
-    requires public java.management;
-    requires public java.naming;
-    requires public java.prefs;
-    requires public java.security.jgss;
-    requires public java.security.sasl;
-    requires public java.sql.rowset;
-    requires public java.xml.crypto;
+    requires transitive java.compact2;
+    requires transitive java.compiler;
+    requires transitive java.instrument;
+    requires transitive java.management;
+    requires transitive java.naming;
+    requires transitive java.prefs;
+    requires transitive java.security.jgss;
+    requires transitive java.security.sasl;
+    requires transitive java.sql.rowset;
+    requires transitive java.xml.crypto;
 }
 
--- a/jdk/src/java.desktop/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.desktop/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,8 +28,8 @@
  * accessibility, audio, imaging, printing, and JavaBeans.
  */
 module java.desktop {
-    requires public java.datatransfer;
-    requires public java.xml;
+    requires transitive java.datatransfer;
+    requires transitive java.xml;
     requires java.prefs;
 
     exports java.applet;
@@ -91,6 +91,11 @@
     exports com.sun.awt to
         jdk.desktop;
 
+    opens javax.swing.plaf.basic to
+        jdk.jconsole;
+    opens com.sun.java.swing.plaf.windows to
+        jdk.jconsole;
+
     uses java.awt.im.spi.InputMethodDescriptor;
     uses javax.accessibility.AccessibilityProvider;
     uses javax.imageio.spi.ImageInputStreamSpi;
@@ -113,31 +118,44 @@
     provides java.net.ContentHandlerFactory with sun.awt.www.content.MultimediaContentHandlers;
     provides javax.print.PrintServiceLookup with sun.print.PrintServiceLookupProvider;
     provides javax.print.StreamPrintServiceFactory with sun.print.PSStreamPrinterFactory;
-    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiInDeviceProvider;
-    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiOutDeviceProvider;
-    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.RealTimeSequencerProvider;
-    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.SoftProvider;
+
+    provides javax.sound.midi.spi.MidiDeviceProvider with
+        com.sun.media.sound.MidiInDeviceProvider,
+        com.sun.media.sound.MidiOutDeviceProvider,
+        com.sun.media.sound.RealTimeSequencerProvider,
+        com.sun.media.sound.SoftProvider;
+
     provides javax.sound.midi.spi.MidiFileReader with com.sun.media.sound.StandardMidiFileReader;
     provides javax.sound.midi.spi.MidiFileWriter with com.sun.media.sound.StandardMidiFileWriter;
-    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.AudioFileSoundbankReader;
-    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.DLSSoundbankReader;
-    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.JARSoundbankReader;
-    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.SF2SoundbankReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AiffFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AuFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.SoftMidiAudioFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFloatFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveExtensibleFileReader;
-    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AiffFileWriter;
-    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AuFileWriter;
-    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFileWriter;
-    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFloatFileWriter;
-    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AlawCodec;
-    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AudioFloatFormatConverter;
-    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.PCMtoPCMCodec;
-    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.UlawCodec;
-    provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.DirectAudioDeviceProvider;
-    provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.PortMixerProvider;
+
+    provides javax.sound.midi.spi.SoundbankReader with
+         com.sun.media.sound.AudioFileSoundbankReader,
+         com.sun.media.sound.DLSSoundbankReader,
+         com.sun.media.sound.JARSoundbankReader,
+         com.sun.media.sound.SF2SoundbankReader;
+
+    provides javax.sound.sampled.spi.AudioFileReader with
+        com.sun.media.sound.AiffFileReader,
+        com.sun.media.sound.AuFileReader,
+        com.sun.media.sound.SoftMidiAudioFileReader,
+        com.sun.media.sound.WaveFileReader,
+        com.sun.media.sound.WaveFloatFileReader,
+        com.sun.media.sound.WaveExtensibleFileReader;
+
+    provides javax.sound.sampled.spi.AudioFileWriter with
+        com.sun.media.sound.AiffFileWriter,
+        com.sun.media.sound.AuFileWriter,
+        com.sun.media.sound.WaveFileWriter,
+        com.sun.media.sound.WaveFloatFileWriter;
+
+    provides javax.sound.sampled.spi.FormatConversionProvider with
+        com.sun.media.sound.AlawCodec,
+        com.sun.media.sound.AudioFloatFormatConverter,
+        com.sun.media.sound.PCMtoPCMCodec,
+        com.sun.media.sound.UlawCodec;
+
+    provides javax.sound.sampled.spi.MixerProvider with
+        com.sun.media.sound.DirectAudioDeviceProvider,
+        com.sun.media.sound.PortMixerProvider;
 }
 
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,6 +27,9 @@
 
 import java.lang.reflect.Module;
 import java.security.ProtectionDomain;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.jar.JarFile;
 
 /*
@@ -660,19 +663,62 @@
     setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
 
     /**
-     * Updates a module to read another module.
+     * Redefine a module to expand the set of modules that it reads, the set of
+     * packages that it exports or opens, or the services that it uses or
+     * provides. This method facilitates the instrumentation of code in named
+     * modules where that instrumentation requires changes to the set of modules
+     * that are read, the packages that are exported or open, or the services
+     * that are used or provided.
+     *
+     * <p> This method cannot reduce the set of modules that a module reads, nor
+     * reduce the set of packages that it exports or opens, nor reduce the set
+     * of services that it uses or provides. This method is a no-op when invoked
+     * to redefine an unnamed module. </p>
      *
-     * Agents that instrument code in named modules may need to arrange for the
-     * modules to read other modules. This method is equivalent to code in {@code
-     * module} calling {@link Module#addReads(Module) addReads} to read {@code
-     * other}.
+     * <p> When expanding the services that a module uses or provides then the
+     * onus is on the agent to ensure that the service type will be accessible at
+     * each instrumentation site where the service type is used. This method
+     * does not check if the service type is a member of the module or in a
+     * package exported to the module by another module that it reads. </p>
+     *
+     * <p> The {@code extraExports} parameter is the map of additional packages
+     * to export. The {@code extraOpens} parameter is the map of additional
+     * packages to open. In both cases, the map key is the fully-qualified name
+     * of the package as defined in section 6.5.3 of
+     * <cite>The Java&trade; Language Specification </cite>, for example, {@code
+     * "java.lang"}. The map value is the non-empty set of modules that the
+     * package should be exported or opened to. </p>
      *
-     * @param module the module to update
-     * @param other the module to read
-     * @throws NullPointerException if either module is {@code null}
+     * <p> The {@code extraProvides} parameter is the additional service providers
+     * for the module to provide. The map key is the service type. The map value
+     * is the non-empty list of implementation types, each of which is a member
+     * of the module and an implementation of the service. </p>
+     *
+     * <p> This method is safe for concurrent use and so allows multiple agents
+     * to instrument and update the same module at around the same time. </p>
      *
+     * @param module the module to redefine
+     * @param extraReads the possibly-empty set of additional modules to read
+     * @param extraExports the possibly-empty map of additional packages to export
+     * @param extraOpens the possibly-empty map of additional packages to open
+     * @param extraUses the possibly-empty set of additional services to use
+     * @param extraProvides the possibly-empty map of additional services to provide
+     *
+     * @throws IllegalArgumentException
+     *         If {@code extraExports} or {@code extraOpens} contains a key
+     *         that is not a package in the module; if {@code extraExports} or
+     *         {@code extraOpens} maps a key to an empty set; if a value in the
+     *         {@code extraProvides} map contains a service provider type that
+     *         is not a member of the module or an implementation of the service;
+     *         or {@code extraProvides} maps a key to an empty list
+     * @throws NullPointerException if any of the arguments are {@code null} or
+     *         any of the Sets or Maps contains a {@code null} key or value
      * @since 9
-     * @see Module#canRead(Module)
      */
-    void addModuleReads(Module module, Module other);
+    void redefineModule(Module module,
+                        Set<Module> extraReads,
+                        Map<String, Set<Module>> extraExports,
+                        Map<String, Set<Module>> extraOpens,
+                        Set<Class<?>> extraUses,
+                        Map<Class<?>, List<Class<?>>> extraProvides);
 }
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html	Wed Jul 05 22:32:06 2017 +0200
@@ -277,15 +277,6 @@
 
 <h3>Instrumenting code in modules</h3>
 
-Agents that instrument code in named modules may need to arrange for the
-modules to read other modules. If code is instrumented to invoke a method
-in a support class in another module, then the module of the instrumented
-code should read the module of the supporting class. Furthermore, the
-supporting class will only be accessible to the instrumented code if
-it is <code>public</code> and in a package that is exported by its module.
-Agents can use {@link Instrumentation#addModuleReads addModuleReads} to update
-a module to read another.
-<p>
 As an aid to agents that deploy supporting classes on the search path of the
 bootstrap class loader, or the search path of the class loader that loads
 the main agent class, the Java virtual machine arranges for the module of
--- a/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,17 +29,22 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Module;
 import java.lang.reflect.AccessibleObject;
-
 import java.lang.instrument.ClassFileTransformer;
 import java.lang.instrument.ClassDefinition;
 import java.lang.instrument.Instrumentation;
-
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
+import java.util.Collections;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarFile;
 
-import java.util.Objects;
-import java.util.jar.JarFile;
+import jdk.internal.module.Modules;
 
 /*
  * Copyright 2003 Wily Technology, Inc.
@@ -228,10 +233,100 @@
     }
 
     @Override
-    public void addModuleReads(Module module, Module other) {
-        Objects.requireNonNull(module);
-        Objects.requireNonNull(other);
-        jdk.internal.module.Modules.addReads(module, other);
+    public void redefineModule(Module module,
+                               Set<Module> extraReads,
+                               Map<String, Set<Module>> extraExports,
+                               Map<String, Set<Module>> extraOpens,
+                               Set<Class<?>> extraUses,
+                               Map<Class<?>, List<Class<?>>> extraProvides)
+    {
+        if (!module.isNamed())
+            return;
+
+        // copy and check reads
+        extraReads = new HashSet<>(extraReads);
+        if (extraReads.contains(null))
+            throw new NullPointerException("'extraReads' contains null");
+
+        // copy and check exports and opens
+        extraExports = cloneAndCheckMap(module, extraExports);
+        extraOpens = cloneAndCheckMap(module, extraOpens);
+
+        // copy and check uses
+        extraUses = new HashSet<>(extraUses);
+        if (extraUses.contains(null))
+            throw new NullPointerException("'extraUses' contains null");
+
+        // copy and check provides
+        Map<Class<?>, List<Class<?>>> tmpProvides = new HashMap<>();
+        for (Map.Entry<Class<?>, List<Class<?>>> e : extraProvides.entrySet()) {
+            Class<?> service = e.getKey();
+            if (service == null)
+                throw new NullPointerException("'extraProvides' contains null");
+            List<Class<?>> providers = new ArrayList<>(e.getValue());
+            if (providers.isEmpty())
+                throw new IllegalArgumentException("list of providers is empty");
+            providers.forEach(p -> {
+                if (p.getModule() != module)
+                    throw new IllegalArgumentException(p + " not in " + module);
+                if (!service.isAssignableFrom(p))
+                    throw new IllegalArgumentException(p + " is not a " + service);
+            });
+            tmpProvides.put(service, providers);
+        }
+        extraProvides = tmpProvides;
+
+
+        // update reads
+        extraReads.forEach(m -> Modules.addReads(module, m));
+
+        // update exports
+        for (Map.Entry<String, Set<Module>> e : extraExports.entrySet()) {
+            String pkg = e.getKey();
+            Set<Module> targets = e.getValue();
+            targets.forEach(m -> Modules.addExports(module, pkg, m));
+        }
+
+        // update opens
+        for (Map.Entry<String, Set<Module>> e : extraOpens.entrySet()) {
+            String pkg = e.getKey();
+            Set<Module> targets = e.getValue();
+            targets.forEach(m -> Modules.addOpens(module, pkg, m));
+        }
+
+        // update uses
+        extraUses.forEach(service -> Modules.addUses(module, service));
+
+        // update provides
+        for (Map.Entry<Class<?>, List<Class<?>>> e : extraProvides.entrySet()) {
+            Class<?> service = e.getKey();
+            List<Class<?>> providers = e.getValue();
+            providers.forEach(p -> Modules.addProvides(module, service, p));
+        }
+    }
+
+    private Map<String, Set<Module>>
+        cloneAndCheckMap(Module module, Map<String, Set<Module>> map)
+    {
+        if (map.isEmpty())
+            return Collections.emptyMap();
+
+        Map<String, Set<Module>> result = new HashMap<>();
+        Set<String> packages = Set.of(module.getPackages());
+        for (Map.Entry<String, Set<Module>> e : map.entrySet()) {
+            String pkg = e.getKey();
+            if (pkg == null)
+                throw new NullPointerException("package cannot be null");
+            if (!packages.contains(pkg))
+                throw new IllegalArgumentException(pkg + " not in module");
+            Set<Module> targets = new HashSet<>(e.getValue());
+            if (targets.isEmpty())
+                throw new IllegalArgumentException("set of targets is empty");
+            if (targets.contains(null))
+                throw new NullPointerException("set of targets cannot include null");
+            result.put(pkg, targets);
+        }
+        return result;
     }
 
 
--- a/jdk/src/java.logging/share/classes/java/util/logging/Level.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.logging/share/classes/java/util/logging/Level.java	Wed Jul 05 22:32:06 2017 +0200
@@ -40,6 +40,8 @@
 import java.util.ResourceBundle;
 import java.util.function.Function;
 import jdk.internal.loader.ClassLoaderValue;
+import jdk.internal.misc.JavaUtilResourceBundleAccess;
+import jdk.internal.misc.SharedSecrets;
 
 /**
  * The Level class defines a set of standard logging levels that
@@ -74,7 +76,11 @@
  */
 
 public class Level implements java.io.Serializable {
-    private static final String defaultBundle = "sun.util.logging.resources.logging";
+    private static final String defaultBundle =
+        "sun.util.logging.resources.logging";
+
+    private static final JavaUtilResourceBundleAccess RB_ACCESS =
+        SharedSecrets.getJavaUtilResourceBundleAccess();
 
     /**
      * @serial  The non-localized name of the level.
@@ -280,7 +286,7 @@
         // or its defining class loader, if it's unnamed module,
         // of this Level instance that can be a custom Level subclass;
         Module module = this.getClass().getModule();
-        ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName,
+        ResourceBundle rb = RB_ACCESS.getBundle(resourceBundleName,
                 newLocale, module);
 
         final String localizedName = rb.getString(name);
--- a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,6 +38,9 @@
 import java.util.ResourceBundle;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Supplier;
+
+import jdk.internal.misc.JavaUtilResourceBundleAccess;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import static jdk.internal.logger.DefaultLoggerFinder.isSystem;
@@ -256,8 +259,8 @@
     private static final LoggerBundle NO_RESOURCE_BUNDLE =
             new LoggerBundle(null, null);
 
-    private static final RuntimePermission GET_CLASS_LOADER_PERMISSION =
-            new RuntimePermission("getClassLoader");
+    private static final JavaUtilResourceBundleAccess RB_ACCESS =
+            SharedSecrets.getJavaUtilResourceBundleAccess();
 
     // A value class that holds the logger configuration data.
     // This configuration can be shared between an application logger
@@ -2180,9 +2183,7 @@
         if (!useCallersModule || callerModule == null || !callerModule.isNamed()) {
             try {
                 Module mod = cl.getUnnamedModule();
-                PrivilegedAction<ResourceBundle> pa = () ->
-                    ResourceBundle.getBundle(name, currentLocale, mod);
-                catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION);
+                catalog = RB_ACCESS.getBundle(name, currentLocale, mod);
                 catalogName = name;
                 catalogLocale = currentLocale;
                 return catalog;
@@ -2226,9 +2227,7 @@
             // Try with the caller's module
             try {
                 // Use the caller's module
-                PrivilegedAction<ResourceBundle> pa = () ->
-                    ResourceBundle.getBundle(name, currentLocale, callerModule);
-                catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION);
+                catalog = RB_ACCESS.getBundle(name, currentLocale, callerModule);
                 catalogName = name;
                 catalogLocale = currentLocale;
                 return catalog;
--- a/jdk/src/java.management/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.management/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,7 +30,7 @@
  * JVM and other components in the Java runtime.
  */
 module java.management {
-    requires public java.rmi;
+    requires transitive java.rmi;
     requires java.logging;
     requires java.naming;
 
--- a/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -625,26 +625,6 @@
                 // that has no from method to be embeded in another class.
             }
 
-            // check if a static "toCompositeData" method exists
-            try {
-                toMethod = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
-                    public Method run() throws NoSuchMethodException {
-                        Method m = javaClass.getDeclaredMethod("toCompositeData", javaClass);
-                        if (m != null
-                                && CompositeData.class.isAssignableFrom(m.getReturnType())
-                                && Modifier.isStatic(m.getModifiers())) {
-                            m.setAccessible(true);
-                            return m;
-                        } else {
-                            return null;
-                        }
-                    }
-                });
-            } catch (PrivilegedActionException e) {
-                // ignore NoSuchMethodException since we allow classes
-                // that has no from method to be embeded in another class.
-            }
-
             if (COMPOSITE_DATA_CLASS.isAssignableFrom(c)) {
                 // c implements CompositeData - set openType to null
                 // defer generating the CompositeType
--- a/jdk/src/java.se.ee/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.se.ee/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,16 +29,17 @@
  * This module requires {@code java.se} and supplements it with modules
  * that define CORBA and Java EE APIs. These modules are upgradeable.
  */
+@SuppressWarnings("deprecation")
 module java.se.ee {
 
-    requires public java.se;
+    requires transitive java.se;
 
     // Upgradeable modules for Java EE technologies
-    requires public java.activation;
-    requires public java.annotations.common;
-    requires public java.corba;
-    requires public java.transaction;
-    requires public java.xml.bind;
-    requires public java.xml.ws;
+    requires transitive java.activation;
+    requires transitive java.annotations.common;
+    requires transitive java.corba;
+    requires transitive java.transaction;
+    requires transitive java.xml.bind;
+    requires transitive java.xml.ws;
 
 }
--- a/jdk/src/java.se/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.se/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -31,8 +31,8 @@
  * required by {@code java.se.ee}.
  */
 module java.se {
-    requires public java.compact3;
-    requires public java.datatransfer;
-    requires public java.desktop;
-    requires public java.httpclient;
+    requires transitive java.compact3;
+    requires transitive java.datatransfer;
+    requires transitive java.desktop;
+    requires transitive java.httpclient;
 }
--- a/jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -63,6 +63,7 @@
             answered = true;
             PasswordAuthentication passAuth =
                     Authenticator.requestPasswordAuthentication(
+                    hci.authenticator,
                     hci.host, hci.addr, hci.port, hci.protocol,
                     hci.prompt, hci.scheme, hci.url, hci.authType);
             /**
--- a/jdk/src/java.sql.rowset/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.sql.rowset/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,9 +27,9 @@
  * Defines the JDBC RowSet API.
  */
 module java.sql.rowset {
-    requires public java.logging;
-    requires public java.naming;
-    requires public java.sql;
+    requires transitive java.logging;
+    requires transitive java.naming;
+    requires transitive java.sql;
 
     exports javax.sql.rowset;
     exports javax.sql.rowset.serial;
--- a/jdk/src/java.sql/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.sql/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,8 +27,8 @@
  * Defines the JDBC API.
  */
 module java.sql {
-    requires public java.logging;
-    requires public java.xml;
+    requires transitive java.logging;
+    requires transitive java.xml;
 
     exports java.sql;
     exports javax.sql;
--- a/jdk/src/java.transaction/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.transaction/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,7 +30,7 @@
  * exceptions by the 'Java Language to IDL Mapping Specification'.
  */
 module java.transaction {
-    requires public java.rmi;
+    requires transitive java.rmi;
     exports javax.transaction;
 }
 
--- a/jdk/src/java.xml.crypto/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/java.xml.crypto/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,7 @@
  * Defines an API for XML cryptography.
  */
 module java.xml.crypto {
-    requires public java.xml;
+    requires transitive java.xml;
     requires java.logging;
 
     exports javax.xml.crypto;
--- a/jdk/src/jdk.accessibility/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.accessibility/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,7 @@
  */
 
 module jdk.accessibility {
-    requires public java.desktop;
+    requires transitive java.desktop;
     exports com.sun.java.accessibility.util;
 }
 
--- a/jdk/src/jdk.attach/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.attach/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Defines the attach API.
+ */
 module jdk.attach {
     requires jdk.jvmstat;
 
--- a/jdk/src/jdk.desktop/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.desktop/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,7 @@
  */
 
 module jdk.desktop {
-    requires public java.desktop;
+    requires transitive java.desktop;
 
     exports jdk.awt;
 }
--- a/jdk/src/jdk.internal.le/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.internal.le/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Internal API for line editing
+ */
 module jdk.internal.le {
     exports jdk.internal.jline to
         jdk.scripting.nashorn.shell,
--- a/jdk/src/jdk.internal.opt/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.internal.opt/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Internal option processing API
+ */
 module jdk.internal.opt {
     exports jdk.internal.joptsimple to jdk.jlink, jdk.jshell;
 }
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,6 +30,7 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Version;
 import java.lang.module.ModuleFinder;
@@ -58,6 +59,7 @@
 
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Checks;
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleInfoExtender;
 import jdk.internal.util.jar.JarIndex;
@@ -80,7 +82,7 @@
     String fname, mname, ename;
     String zname = "";
     String rootjar = null;
-    Set<String> concealedPackages = new HashSet<>();
+    Set<String> concealedPackages = new HashSet<>(); // used by Validator
 
     private static final int BASE_VERSION = 0;
 
@@ -90,6 +92,13 @@
         final File file;
         final boolean isDir;
 
+        Entry(File file, String basename, String entryname) {
+            this.file = file;
+            this.isDir = file.isDirectory();
+            this.basename = basename;
+            this.entryname = entryname;
+        }
+
         Entry(int version, File file) {
             this.file = file;
             String path = file.getPath();
@@ -105,6 +114,21 @@
             entryname = en.entryName;
         }
 
+        /**
+         * Returns a new Entry that trims the versions directory.
+         *
+         * This entry should be a valid entry matching the given version.
+         */
+        Entry toVersionedEntry(int version) {
+            assert isValidVersionedEntry(this, version);
+
+            if (version == BASE_VERSION)
+                return this;
+
+            EntryName en = new EntryName(trimVersionsDir(basename, version), version);
+            return new Entry(this.file, en.baseName, en.entryName);
+        }
+
         @Override
         public boolean equals(Object o) {
             if (this == o) return true;
@@ -488,7 +512,9 @@
             } else if (printModuleDescriptor) {
                 boolean found;
                 if (fname != null) {
-                    found = printModuleDescriptor(new ZipFile(fname));
+                    try (ZipFile zf = new ZipFile(fname)) {
+                        found = printModuleDescriptor(zf);
+                    }
                 } else {
                     try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
                         found = printModuleDescriptor(fin);
@@ -748,6 +774,12 @@
         /* parse file arguments */
         int n = args.length - count;
         if (n > 0) {
+            if (printModuleDescriptor) {
+                // "--print-module-descriptor/-d" does not require file argument(s)
+                error(formatMsg("error.bad.dflag", args[count]));
+                usageError();
+                return false;
+            }
             int version = BASE_VERSION;
             int k = 0;
             String[] nameBuf = new String[n];
@@ -822,21 +854,27 @@
         return true;
     }
 
-    private static String toPackageName(ZipEntry entry) {
-        return toPackageName(entry.getName());
+    /*
+     * Add the package of the given resource name if it's a .class
+     * or a resource in a named package.
+     */
+    boolean addPackageIfNamed(String name) {
+        if (name.startsWith(VERSIONS_DIR)) {
+            throw new InternalError(name);
+        }
+
+        String pn = toPackageName(name);
+        // add if this is a class or resource in a package
+        if (Checks.isJavaIdentifier(pn)) {
+            packages.add(pn);
+            return true;
+        }
+
+        return false;
     }
 
     private static String toPackageName(String path) {
-        assert path.endsWith(".class");
-        int index;
-        if (path.startsWith(VERSIONS_DIR)) {
-            index = path.indexOf('/', VERSIONS_DIR.length());
-            if (index <= 0) {
-                return "";
-            }
-            path = path.substring(index + 1);
-        }
-        index = path.lastIndexOf('/');
+        int index = path.lastIndexOf('/');
         if (index != -1) {
             return path.substring(0, index).replace('/', '.');
         } else {
@@ -844,6 +882,48 @@
         }
     }
 
+    /*
+     * Returns true if the given entry is a valid entry of the given version.
+     */
+    private boolean isValidVersionedEntry(Entry entry, int version) {
+        String name = entry.basename;
+        if (name.startsWith(VERSIONS_DIR) && version != BASE_VERSION) {
+            int i = name.indexOf('/', VERSIONS_DIR.length());
+            // name == -1 -> not a versioned directory, something else
+            if (i == -1)
+                return false;
+            try {
+                String v = name.substring(VERSIONS_DIR.length(), i);
+                return Integer.valueOf(v) == version;
+            } catch (NumberFormatException x) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * Trim META-INF/versions/$version/ from the given name if the
+     * given name is a versioned entry of the given version; or
+     * of any version if the given version is BASE_VERSION
+     */
+    private String trimVersionsDir(String name, int version) {
+        if (name.startsWith(VERSIONS_DIR)) {
+            int i = name.indexOf('/', VERSIONS_DIR.length());
+            if (i >= 0) {
+                try {
+                    String v = name.substring(VERSIONS_DIR.length(), i);
+                    if (version == BASE_VERSION || Integer.valueOf(v) == version) {
+                        return name.substring(i + 1, name.length());
+                    }
+                } catch (NumberFormatException x) {}
+            }
+            throw new InternalError("unexpected versioned entry: " +
+                    name + " version " + version);
+        }
+        return name;
+    }
+
     /**
      * Expands list of files to process into full list of all files that
      * can be found by recursively descending directories.
@@ -865,28 +945,47 @@
             else
                 f = new File(dir, files[i]);
 
-            Entry entry = new Entry(version, f);
-            String entryName = entry.entryname;
-
+            Entry e = new Entry(version, f);
+            String entryName = e.entryname;
+            Entry entry = e;
+            if (e.basename.startsWith(VERSIONS_DIR) && isValidVersionedEntry(e, version)) {
+                entry = e.toVersionedEntry(version);
+            }
             if (f.isFile()) {
                 if (entryName.endsWith(MODULE_INFO)) {
                     moduleInfoPaths.put(entryName, f.toPath());
                     if (isUpdate)
                         entryMap.put(entryName, entry);
-                } else if (entries.add(entry)) {
-                    jarEntries.add(entryName);
-                    if (entry.basename.endsWith(".class"))
-                        packages.add(toPackageName(entry.basename));
-                    if (isUpdate)
-                        entryMap.put(entryName, entry);
+                } else if (isValidVersionedEntry(entry, version)) {
+                    if (entries.add(entry)) {
+                        jarEntries.add(entryName);
+                        // add the package if it's a class or resource
+                        addPackageIfNamed(trimVersionsDir(entry.basename, version));
+                        if (isUpdate)
+                            entryMap.put(entryName, entry);
+                    }
+                } else {
+                    error(formatMsg2("error.release.unexpected.versioned.entry",
+                                      entry.basename, String.valueOf(version)));
+                    ok = false;
                 }
             } else if (f.isDirectory()) {
-                if (entries.add(entry)) {
-                    if (isUpdate) {
-                        entryMap.put(entryName, entry);
+                if (isValidVersionedEntry(entry, version)) {
+                    if (entries.add(entry)) {
+                        if (isUpdate) {
+                            entryMap.put(entryName, entry);
+                        }
                     }
-                    expand(f, f.list(), isUpdate, moduleInfoPaths, version);
+                } else if (entry.basename.equals(VERSIONS_DIR)) {
+                    if (vflag) {
+                        output(formatMsg("out.ignore.entry", entry.basename));
+                    }
+                } else {
+                    error(formatMsg2("error.release.unexpected.versioned.entry",
+                                      entry.basename, String.valueOf(version)));
+                    ok = false;
                 }
+                expand(f, f.list(), isUpdate, moduleInfoPaths, version);
             } else {
                 error(formatMsg("error.nosuch.fileordir", String.valueOf(f)));
                 ok = false;
@@ -1047,6 +1146,7 @@
             } else if (moduleInfos != null && isModuleInfoEntry) {
                 moduleInfos.putIfAbsent(name, readModuleInfo(zis));
             } else {
+                boolean isDir = e.isDirectory();
                 if (!entryMap.containsKey(name)) { // copy the old stuff
                     // do our own compression
                     ZipEntry e2 = new ZipEntry(name);
@@ -1065,11 +1165,14 @@
                     addFile(zos, ent);
                     entryMap.remove(name);
                     entries.remove(ent);
+                    isDir = ent.isDir;
                 }
 
                 jarEntries.add(name);
-                if (name.endsWith(".class"))
-                    packages.add(toPackageName(name));
+                if (!isDir) {
+                    // add the package if it's a class or resource
+                    addPackageIfNamed(trimVersionsDir(name, BASE_VERSION));
+                }
             }
         }
 
@@ -1850,13 +1953,13 @@
 
     // Modular jar support
 
-    static <T> String toString(Set<T> set,
+    static <T> String toString(Collection<T> c,
                                CharSequence prefix,
                                CharSequence suffix ) {
-        if (set.isEmpty())
+        if (c.isEmpty())
             return "";
 
-        return set.stream().map(e -> e.toString())
+        return c.stream().map(e -> e.toString())
                            .collect(joining(", ", prefix, suffix));
     }
 
@@ -1890,7 +1993,7 @@
         return false;
     }
 
-    static <T> String toString(Set<T> set) {
+    static <T> String toString(Collection<T> set) {
         if (set.isEmpty()) { return ""; }
         return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
                   .collect(joining(" "));
@@ -1903,7 +2006,10 @@
     {
         ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);
         StringBuilder sb = new StringBuilder();
-        sb.append("\n").append(md.toNameAndVersion());
+        sb.append("\n");
+        if (md.isOpen())
+            sb.append("open ");
+        sb.append(md.toNameAndVersion());
 
         md.requires().stream()
             .sorted(Comparator.comparing(Requires::name))
@@ -1921,10 +2027,17 @@
             .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.opens().stream()
+            .sorted(Comparator.comparing(Opens::source))
+            .forEach(p -> sb.append("\n  opens ").append(p));
 
-        md.provides().values().stream()
+        Set<String> concealed = new HashSet<>(md.packages());
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        md.opens().stream().map(Opens::source).forEach(concealed::remove);
+        concealed.stream().sorted()
+            .forEach(p -> sb.append("\n  contains ").append(p));
+
+        md.provides().stream()
             .sorted(Comparator.comparing(Provides::service))
             .forEach(p -> sb.append("\n  provides ").append(p.service())
                             .append(" with ")
@@ -1957,10 +2070,9 @@
     {
         ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes));
         Set<String> missing = md.provides()
-                                .values()
                                 .stream()
                                 .map(Provides::providers)
-                                .flatMap(Set::stream)
+                                .flatMap(List::stream)
                                 .filter(p -> !jarEntries.contains(toBinaryName(p)))
                                 .collect(Collectors.toSet());
         if (missing.size() > 0) {
@@ -1988,22 +2100,17 @@
             ModuleDescriptor vd = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue()));
             if (!(isValidVersionedDescriptor(vd, rd)))
                 return false;
-            e.setValue(extendedInfoBytes(rd, vd, e.getValue(), concealedPackages));
+            e.setValue(extendedInfoBytes(rd, vd, e.getValue(), packages));
         }
         return true;
     }
 
-    private Set<String> findConcealedPackages(ModuleDescriptor md){
+    private Set<String> findConcealedPackages(ModuleDescriptor md) {
         Objects.requireNonNull(md);
-
-        Set<String> exports = md.exports()
-                .stream()
-                .map(Exports::source)
-                .collect(toSet());
-
-        return packages.stream()
-                .filter(p -> !exports.contains(p))
-                .collect(toSet());
+        Set<String> concealed = new HashSet<>(packages);
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        md.opens().stream().map(Opens::source).forEach(concealed::remove);
+        return concealed;
     }
 
     private static boolean isPlatformModule(String name) {
@@ -2034,8 +2141,8 @@
             for (Requires r : vd.requires()) {
                 if (rootRequires.contains(r)) {
                     continue;
-                } else if (r.modifiers().contains(Requires.Modifier.PUBLIC)) {
-                    fatalError(getMsg("error.versioned.info.requires.public"));
+                } else if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) {
+                    fatalError(getMsg("error.versioned.info.requires.transitive"));
                     return false;
                 } else if (!isPlatformModule(r.name())) {
                     fatalError(getMsg("error.versioned.info.requires.added"));
@@ -2056,6 +2163,10 @@
             fatalError(getMsg("error.versioned.info.exports.notequal"));
             return false;
         }
+        if (!rd.opens().equals(vd.opens())) {
+            fatalError(getMsg("error.versioned.info.opens.notequal"));
+            return false;
+        }
         if (!rd.provides().equals(vd.provides())) {
             fatalError(getMsg("error.versioned.info.provides.notequal"));
             return false;
@@ -2074,15 +2185,15 @@
     private byte[] extendedInfoBytes(ModuleDescriptor rootDescriptor,
                                      ModuleDescriptor md,
                                      byte[] miBytes,
-                                     Set<String> conceals)
+                                     Set<String> packages)
         throws IOException
     {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         InputStream is = new ByteArrayInputStream(miBytes);
         ModuleInfoExtender extender = ModuleInfoExtender.newExtender(is);
 
-        // Add (or replace) the ConcealedPackages attribute
-        extender.conceals(conceals);
+        // Add (or replace) the Packages attribute
+        extender.packages(packages);
 
         // --main-class
         if (ename != null)
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -44,6 +44,8 @@
 error.bad.eflag=\
 	'e' flag and manifest with the 'Main-Class' attribute cannot be specified \n\
 	 together!
+error.bad.dflag=\
+        '-d, --print-module-descriptor' option requires no input file(s) to be specified: {0}
 error.nosuch.fileordir=\
         {0} : no such file or directory
 error.write.file=\
@@ -67,14 +69,16 @@
         in the root
 error.versioned.info.name.notequal=\
         module-info.class in a versioned directory contains incorrect name
-error.versioned.info.requires.public=\
-        module-info.class in a versioned directory contains additional "requires public"
+error.versioned.info.requires.transitive=\
+        module-info.class in a versioned directory contains additional "requires transitive"
 error.versioned.info.requires.added=\
         module-info.class in a versioned directory contains additional "requires"
 error.versioned.info.requires.dropped=\
         module-info.class in a versioned directory contains missing "requires"
 error.versioned.info.exports.notequal=\
         module-info.class in a versioned directory contains different "exports"
+error.versioned.info.opens.notequal=\
+        module-info.class in a versioned directory contains different "opens"
 error.versioned.info.provides.notequal=\
         module-info.class in a versioned directory contains different "provides"
 error.invalid.versioned.module.attribute=\
@@ -85,6 +89,8 @@
         release {0} not valid
 error.release.value.toosmall=\
         release {0} not valid, must be >= 9
+error.release.unexpected.versioned.entry=\
+        unexpected versioned entry {0} for release {1}
 error.validator.jarfile.exception=\
         can not validate {0}: {1}
 error.validator.jarfile.invalid=\
@@ -104,14 +110,16 @@
 error.validator.different.api=\
         entry: {0}, contains a class with different api from earlier version
 error.validator.names.mismatch=\
-         entry: {0}, contains a class with internal name {1}, names do not match
+        entry: {0}, contains a class with internal name {1}, names do not match
 warn.validator.identical.entry=\
-        warning - entry: {0} contains a class that is identical to an entry already in the jar
+        Warning: entry {0} contains a class that\n\
+        is identical to an entry already in the jar
 warn.validator.resources.with.same.name=\
-         warning - entry: {0}, multiple resources with same name
+        Warning: entry {0}, multiple resources with same name
 warn.validator.concealed.public.class=\
-         warning - entry {0} is a public class in a concealed package, \n\
-         placing this jar on the class path will result in incompatible public interfaces
+        Warning: entry {0} is a public class\n\
+        in a concealed package, placing this jar on the class path will result\n\
+        in incompatible public interfaces
 out.added.manifest=\
         added manifest
 out.added.module-info=\
--- a/jdk/src/jdk.jconsole/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jconsole/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,8 +24,8 @@
  */
 
 module jdk.jconsole {
-    requires public java.desktop;
-    requires public java.management;
+    requires transitive java.desktop;
+    requires transitive java.management;
     requires java.logging;
     requires java.rmi;
     requires jdk.attach;
--- a/jdk/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java	Wed Jul 05 22:32:06 2017 +0200
@@ -40,8 +40,8 @@
 import java.util.WeakHashMap;
 
 import java.util.concurrent.ExecutionException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
 import javax.management.JMException;
 import javax.management.MBeanInfo;
 import javax.management.MBeanAttributeInfo;
@@ -81,7 +81,7 @@
 public class XMBeanAttributes extends XTable {
 
     final Logger LOGGER =
-            Logger.getLogger(XMBeanAttributes.class.getPackage().getName());
+            System.getLogger(XMBeanAttributes.class.getPackage().getName());
 
     private final static String[] columnNames =
     {Messages.NAME,
@@ -190,8 +190,8 @@
     }
 
     public void cancelCellEditing() {
-        if (LOGGER.isLoggable(Level.FINER)) {
-            LOGGER.finer("Cancel Editing Row: "+getEditingRow());
+        if (LOGGER.isLoggable(Level.TRACE)) {
+            LOGGER.log(Level.TRACE, "Cancel Editing Row: "+getEditingRow());
         }
         final TableCellEditor tableCellEditor = getCellEditor();
         if (tableCellEditor != null) {
@@ -200,8 +200,8 @@
     }
 
     public void stopCellEditing() {
-        if (LOGGER.isLoggable(Level.FINER)) {
-            LOGGER.finer("Stop Editing Row: "+getEditingRow());
+        if (LOGGER.isLoggable(Level.TRACE)) {
+            LOGGER.log(Level.TRACE, "Stop Editing Row: "+getEditingRow());
         }
         final TableCellEditor tableCellEditor = getCellEditor();
         if (tableCellEditor != null) {
@@ -211,8 +211,8 @@
 
     @Override
     public final boolean editCellAt(final int row, final int column, EventObject e) {
-        if (LOGGER.isLoggable(Level.FINER)) {
-            LOGGER.finer("editCellAt(row="+row+", col="+column+
+        if (LOGGER.isLoggable(Level.TRACE)) {
+            LOGGER.log(Level.TRACE, "editCellAt(row="+row+", col="+column+
                     ", e="+e+")");
         }
         if (JConsole.isDebug()) {
@@ -1002,8 +1002,9 @@
                 Object tableValue = model.getValueAt(e.getFirstRow(),
                                                  e.getColumn());
 
-                if (LOGGER.isLoggable(Level.FINER)) {
-                    LOGGER.finer("tableChanged: firstRow="+e.getFirstRow()+
+                if (LOGGER.isLoggable(Level.TRACE)) {
+                    LOGGER.log(Level.TRACE,
+                        "tableChanged: firstRow="+e.getFirstRow()+
                         ", lastRow="+e.getLastRow()+", column="+e.getColumn()+
                         ", value="+tableValue);
                 }
--- a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,17 +30,17 @@
  * A module in the target VM.
  * <p>
  * Any method on {@code ModuleReference} which directly or
- * indirectly takes {@code ModuleReference} as an parameter may throw
+ * indirectly takes {@code ModuleReference} as a parameter may throw
  * {@link com.sun.jdi.VMDisconnectedException} if the target VM is
  * disconnected and the {@link com.sun.jdi.event.VMDisconnectEvent} has been or is
  * available to be read from the {@link com.sun.jdi.event.EventQueue}.
  * <p>
  * Any method on {@code ModuleReference} which directly or
- * indirectly takes {@code ModuleReference} as an parameter may throw
+ * indirectly takes {@code ModuleReference} as a parameter may throw
  * {@link com.sun.jdi.VMOutOfMemoryException} if the target VM has run out of memory.
  * <p>
  * Any method on {@code ModuleReference} or which directly or indirectly takes
- * {@code ModuleReference} as parameter may throw
+ * {@code ModuleReference} as a parameter may throw
  * {@link com.sun.jdi.InvalidModuleException} if the mirrored module
  * has been unloaded.
  *
@@ -67,12 +67,4 @@
      * @return the {@link ClassLoaderReference} object for this module.
      */
     ClassLoaderReference classLoader();
-
-    /**
-     * Indicates if this module reads another module.
-     *
-     * @return {@code true} if this module reads {@code other},
-     *         {@code false} otherwise
-     */
-    boolean canRead(ModuleReference other);
 }
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java	Wed Jul 05 22:32:06 2017 +0200
@@ -75,15 +75,4 @@
         }
         return classLoader;
     }
-
-    public synchronized boolean canRead(ModuleReference module) {
-        boolean ret;
-        try {
-            ret = JDWP.ModuleReference.CanRead.
-                process(this.vm, this, (ModuleReferenceImpl)module).canRead;
-        } catch (JDWPException ex) {
-            throw ex.toJDIException();
-        }
-        return ret;
-    }
 }
--- a/jdk/src/jdk.jdi/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jdi/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Defines the Java Debugger Interface.
+ */
 module jdk.jdi {
     requires jdk.attach;
     requires jdk.jdwp.agent;
@@ -37,10 +40,11 @@
     uses com.sun.jdi.connect.spi.TransportService;
 
     // windows shared memory connector providers are added at build time
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.ProcessAttachingConnector;
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.RawCommandLineLauncher;
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SocketAttachingConnector;
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SocketListeningConnector;
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SunCommandLineLauncher;
+    provides com.sun.jdi.connect.Connector with
+        com.sun.tools.jdi.ProcessAttachingConnector,
+        com.sun.tools.jdi.RawCommandLineLauncher,
+        com.sun.tools.jdi.SocketAttachingConnector,
+        com.sun.tools.jdi.SocketListeningConnector,
+        com.sun.tools.jdi.SunCommandLineLauncher;
 }
 
--- a/jdk/src/jdk.jdi/windows/classes/module-info.java.extra	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jdi/windows/classes/module-info.java.extra	Wed Jul 05 22:32:06 2017 +0200
@@ -23,5 +23,6 @@
  * questions.
  */
 
-provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SharedMemoryAttachingConnector;
-provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SharedMemoryListeningConnector;
+provides com.sun.jdi.connect.Connector with
+    com.sun.tools.jdi.SharedMemoryAttachingConnector,
+    com.sun.tools.jdi.SharedMemoryListeningConnector;
--- a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Java Debug Wire Protocol.
+ */
 module jdk.jdwp.agent {
 }
 
--- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c	Wed Jul 05 22:32:06 2017 +0200
@@ -83,36 +83,8 @@
     return JNI_TRUE;
 }
 
-static jboolean
-canRead(PacketInputStream *in, PacketOutputStream *out)
-{
-    static jmethodID method = NULL;
-    JNIEnv *env = getEnv();
-    jboolean can_read;
-    jobject module;
-    jobject source_module;
-
-    if (method == NULL) {
-        method = getMethod(env, jlrM(env), "canRead", "(Ljava/lang/reflect/Module;)Z");
-    }
-    module = inStream_readModuleRef(env, in);
-    if (inStream_error(in)) {
-        return JNI_TRUE;
-    }
-    source_module = inStream_readModuleRef(env, in);
-    if (inStream_error(in)) {
-        return JNI_TRUE;
-    }
-    can_read = JNI_FUNC_PTR(env, CallBooleanMethod)
-        (env, module, method, source_module);
-
-    (void)outStream_writeBoolean(out, can_read);
-    return JNI_TRUE;
-}
-
 
 void *ModuleReference_Cmds[] = { (void *)3
     ,(void *)getName
     ,(void *)getClassLoader
-    ,(void *)canRead
 };
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Wed Jul 05 22:32:06 2017 +0200
@@ -268,7 +268,15 @@
                             resources.getStringTable());
                 }
             }
-            resPool = p.transform(resPool, resMgr.resourcePoolBuilder());
+            try {
+                resPool = p.transform(resPool, resMgr.resourcePoolBuilder());
+            } catch (PluginException pe) {
+                if (JlinkTask.DEBUG) {
+                    System.err.println("Plugin " + p.getName() + " threw exception during transform");
+                    pe.printStackTrace();
+                }
+                throw pe;
+            }
             if (resPool.isEmpty()) {
                 throw new Exception("Invalid resource pool for plugin " + p);
             }
@@ -444,6 +452,7 @@
                         res = res.copyWithContent(bytes);
                     } catch (IOException ex) {
                         if (JlinkTask.DEBUG) {
+                            System.err.println("IOException while reading resource: " + res.path());
                             ex.printStackTrace();
                         }
                         throw new PluginException(ex);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java	Wed Jul 05 22:32:06 2017 +0200
@@ -298,7 +298,15 @@
         List<Plugin> bootPlugins = PluginRepository.getPlugins(Layer.boot());
         for (Plugin bp : bootPlugins) {
             if (Utils.isAutoEnabled(bp)) {
-                bp.configure(Collections.emptyMap());
+                try {
+                    bp.configure(Collections.emptyMap());
+                } catch (IllegalArgumentException e) {
+                    if (JlinkTask.DEBUG) {
+                        System.err.println("Plugin " + bp.getName() + " threw exception with config: {}");
+                        e.printStackTrace();
+                    }
+                    throw e;
+                }
                 plugins.add(bp);
             }
         }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
 import java.io.PrintWriter;
 import java.io.UncheckedIOException;
 import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReference;
 import java.lang.module.ResolutionException;
@@ -191,6 +192,7 @@
                 taskHelper.showVersion(options.fullVersion);
                 return EXIT_OK;
             }
+
             if (taskHelper.getExistingImage() == null) {
                 if (options.modulePath.isEmpty()) {
                     throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true);
@@ -256,7 +258,6 @@
         ImageProvider imageProvider =
                 createImageProvider(finder,
                                     config.getModules(),
-                                    config.getLimitmods(),
                                     config.getByteOrder(),
                                     null,
                                     IGNORE_SIGNING_DEFAULT);
@@ -291,23 +292,43 @@
         postProcessImage(img, config.getPlugins());
     }
 
+    // the token for "all modules on the module path"
+    private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
     private void createImage() throws Exception {
         if (options.output == null) {
             throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true);
         }
-        ModuleFinder finder
-                = newModuleFinder(options.modulePath, options.limitMods, options.addMods);
+
         if (options.addMods.isEmpty()) {
             throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules")
                     .showUsage(true);
         }
+
+        Set<String> roots = new HashSet<>();
+        for (String mod : options.addMods) {
+            if (mod.equals(ALL_MODULE_PATH)) {
+                ModuleFinder finder = modulePathFinder();
+                finder.findAll()
+                      .stream()
+                      .map(ModuleReference::descriptor)
+                      .map(ModuleDescriptor::name)
+                      .forEach(mn -> roots.add(mn));
+            } else {
+                roots.add(mod);
+            }
+        }
+
+        ModuleFinder finder = newModuleFinder(options.modulePath,
+                                              options.limitMods,
+                                              roots);
+
+
         // First create the image provider
         ImageProvider imageProvider = createImageProvider(finder,
-                        options.addMods,
-                        options.limitMods,
-                        options.endian,
-                        options.packagedModulesPath,
-                        options.ignoreSigning);
+                                                          roots,
+                                                          options.endian,
+                                                          options.packagedModulesPath,
+                                                          options.ignoreSigning);
 
         // Then create the Plugin Stack
         ImagePluginStack stack = ImagePluginConfiguration.
@@ -362,21 +383,20 @@
     }
 
     private static ImageProvider createImageProvider(ModuleFinder finder,
-                                                     Set<String> addMods,
-                                                     Set<String> limitMods,
+                                                     Set<String> roots,
                                                      ByteOrder order,
                                                      Path retainModulesPath,
                                                      boolean ignoreSigning)
             throws IOException
     {
-        if (addMods.isEmpty()) {
+        if (roots.isEmpty()) {
             throw new IllegalArgumentException("empty modules and limitmods");
         }
 
         Configuration cf = Configuration.empty()
                 .resolveRequires(finder,
                                  ModuleFinder.of(),
-                                 addMods);
+                                 roots);
 
         Map<String, Path> mods = cf.modules().stream()
             .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
@@ -388,8 +408,8 @@
      * modules, their transitive dependences, plus a set of other modules.
      */
     private static ModuleFinder limitFinder(ModuleFinder finder,
-            Set<String> roots,
-            Set<String> otherMods) {
+                                            Set<String> roots,
+                                            Set<String> otherMods) {
 
         // resolve all root modules
         Configuration cf = Configuration.empty()
@@ -535,40 +555,4 @@
             return image;
         }
     }
-
-    private static 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;
-        }
-
-        boolean matches(String path) {
-            return path.startsWith(jmodDir);
-        }
-
-        static Section getSectionFromName(String dir) {
-            if (Section.NATIVE_LIBS.matches(dir)) {
-                return Section.NATIVE_LIBS;
-            } else if (Section.NATIVE_CMDS.matches(dir)) {
-                return Section.NATIVE_CMDS;
-            } else if (Section.CLASSES.matches(dir)) {
-                return Section.CLASSES;
-            } else if (Section.CONFIG.matches(dir)) {
-                return Section.CONFIG;
-            } else {
-                return Section.UNKNOWN;
-            }
-        }
-    }
 }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java	Wed Jul 05 22:32:06 2017 +0200
@@ -74,7 +74,15 @@
         Objects.requireNonNull(pluginsLayer);
         Plugin plugin = getPlugin(name, pluginsLayer);
         if (plugin != null) {
-            plugin.configure(config);
+            try {
+                plugin.configure(config);
+            } catch (IllegalArgumentException e) {
+                if (JlinkTask.DEBUG) {
+                    System.err.println("Plugin " + plugin.getName() + " threw exception with config: " + config);
+                    e.printStackTrace();
+                }
+                throw e;
+            }
         }
         return plugin;
     }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Wed Jul 05 22:32:06 2017 +0200
@@ -50,24 +50,23 @@
         ModuleDescriptor md = mod.descriptor();
 
         // drop hashes
-        ModuleDescriptor.Builder builder = new ModuleDescriptor.Builder(md.name());
+        ModuleDescriptor.Builder builder = ModuleDescriptor.module(md.name());
         md.requires().stream()
           .forEach(builder::requires);
         md.exports().stream()
           .forEach(builder::exports);
+        md.opens().stream()
+          .forEach(builder::opens);
         md.uses().stream()
           .forEach(builder::uses);
-        md.provides().values().stream()
+        md.provides().stream()
           .forEach(builder::provides);
 
         // build the proper concealed packages
-        Set<String> exps = md.exports().stream()
-            .map(ModuleDescriptor.Exports::source)
-            .collect(Collectors.toSet());
-
-        mod.packages().stream()
-           .filter(pn -> !exps.contains(pn))
-           .forEach(builder::conceals);
+        Set<String> concealed = new HashSet<>(mod.packages());
+        md.exports().stream().map(ModuleDescriptor.Exports::source).forEach(concealed::remove);
+        md.opens().stream().map(ModuleDescriptor.Opens::source).forEach(concealed::remove);
+        concealed.stream().forEach(builder::contains);
 
         md.version().ifPresent(builder::version);
         md.mainClass().ifPresent(builder::mainClass);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java	Wed Jul 05 22:32:06 2017 +0200
@@ -35,6 +35,7 @@
 import java.util.Set;
 import java.util.stream.Stream;
 import jdk.internal.jimage.decompressor.CompressedResourceHeader;
+import jdk.internal.loader.ResourceHelper;
 import jdk.tools.jlink.plugin.ResourcePool;
 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
 import jdk.tools.jlink.plugin.ResourcePoolEntry;
@@ -58,6 +59,14 @@
         return ModuleDescriptor.read(bb);
     }
 
+    /**
+     * Returns true if a resource has an effective package.
+     */
+    public static boolean isNamedPackageResource(String path) {
+        return (path.endsWith(".class") && !path.endsWith("module-info.class")) ||
+                !ResourceHelper.isSimpleResource(path);
+    }
+
     class ResourcePoolModuleImpl implements ResourcePoolModule {
 
         final Map<String, ResourcePoolEntry> moduleContent = new LinkedHashMap<>();
@@ -100,7 +109,7 @@
                 .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")) {
+                    if (isNamedPackageResource(name)) {
                         String pkg = ImageFileCreator.toPackage(name);
                         if (!pkg.isEmpty()) {
                             pkgs.add(pkg);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -421,7 +421,15 @@
                 // we call configure once for each occurrence. It is upto the plugin
                 // to 'merge' and/or 'override' arguments.
                 for (Map<String, String> map : argsMaps) {
-                    plugin.configure(Collections.unmodifiableMap(map));
+                    try {
+                        plugin.configure(Collections.unmodifiableMap(map));
+                    } catch (IllegalArgumentException e) {
+                        if (JlinkTask.DEBUG) {
+                            System.err.println("Plugin " + plugin.getName() + " threw exception with config: " + map);
+                            e.printStackTrace();
+                        }
+                        throw e;
+                    }
                 }
 
                 if (!Utils.isDisabled(plugin)) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeJmodSectionPlugin.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeJmodSectionPlugin.java	Wed Jul 05 22:32:06 2017 +0200
@@ -55,7 +55,7 @@
     public void configure(Map<String, String> config) {
         String arg = config.get(NAME);
         if (arg.isEmpty()) {
-            throw new PluginException("Section name must be specified");
+            throw new IllegalArgumentException("Section name must be specified");
         }
 
         switch (arg) {
@@ -66,7 +66,7 @@
                 filters.add(Type.HEADER_FILE);
                 break;
             default:
-                throw new PluginException("Invalid section name: " + arg);
+                throw new IllegalArgumentException("Invalid section name: " + arg);
         }
     }
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.file.FileSystem;
 import java.nio.file.Files;
 import java.nio.file.PathMatcher;
@@ -177,7 +178,7 @@
                     try {
                         lines = Files.readAllLines(file.toPath());
                     } catch (IOException ex) {
-                        throw new PluginException(ex);
+                        throw new UncheckedIOException(ex);
                     }
 
                     for (String line : lines) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Wed Jul 05 22:32:06 2017 +0200
@@ -115,7 +115,7 @@
                 try (FileInputStream fis = new FileInputStream(operation)) {
                     props.load(fis);
                 } catch (IOException exp) {
-                    throw new RuntimeException(exp);
+                    throw new UncheckedIOException(exp);
                 }
                 props.forEach((k, v) -> release.put(k.toString(), v.toString()));
             }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.PathMatcher;
@@ -35,7 +36,6 @@
 import java.util.Objects;
 import java.util.function.Predicate;
 import jdk.tools.jlink.internal.Utils;
-import jdk.tools.jlink.plugin.PluginException;
 
 /**
  *
@@ -62,7 +62,7 @@
                     try {
                         lines = Files.readAllLines(file.toPath());
                     } catch (IOException ex) {
-                        throw new PluginException(ex);
+                        throw new UncheckedIOException(ex);
                     }
 
                     lines.stream().forEach((line) -> {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,17 +28,18 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.*;
-import java.lang.module.ModuleDescriptor;
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Collection;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
+import java.util.Objects;
 import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.function.IntSupplier;
 
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
@@ -50,16 +51,17 @@
 import jdk.internal.org.objectweb.asm.Opcodes;
 
 import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.plugin.ResourcePool;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.Builder.*;
+import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.SystemModulesClassGenerator.*;
 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
 import jdk.tools.jlink.plugin.ResourcePoolEntry;
 
 /**
- * Jlink plugin to reconstitute module descriptors for installed modules.
- * It will extend module-info.class with ConcealedPackages attribute,
+ * Jlink plugin to reconstitute module descriptors for system modules.
+ * It will extend module-info.class with Packages attribute,
  * if not present. It also determines the number of packages of
  * the boot layer at link time.
  *
@@ -69,16 +71,14 @@
  * @see SystemModules
  */
 public final class SystemModuleDescriptorPlugin implements Plugin {
-    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+    private static final JavaLangModuleAccess JLMA =
+        SharedSecrets.getJavaLangModuleAccess();
 
-    // TODO: packager has the dependency on the plugin name
-    // Keep it as "--installed-modules" until packager removes such
-    // dependency (should not need to specify this plugin since it
-    // is enabled by default)
-    private static final String NAME = "installed-modules";
-    private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
+    private static final String NAME = "system-modules";
+    private static final String DESCRIPTION =
+        PluginsResourceBundle.getDescription(NAME);
+
     private boolean enabled;
-
     public SystemModuleDescriptorPlugin() {
         this.enabled = true;
     }
@@ -106,39 +106,38 @@
         }
     }
 
-
     @Override
     public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
         if (!enabled) {
             throw new PluginException(NAME + " was set");
         }
 
-        Builder builder = new Builder();
+        SystemModulesClassGenerator generator = new SystemModulesClassGenerator();
 
         // generate the byte code to create ModuleDescriptors
         // skip parsing module-info.class and skip name check
         in.moduleView().modules().forEach(module -> {
-            Optional<ResourcePoolEntry> optData = module.findEntry("module-info.class");
-            if (! optData.isPresent()) {
+
+            ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
                 // automatic module not supported yet
-                throw new PluginException("module-info.class not found for " +
-                                          module.name() + " module");
-            }
-            ResourcePoolEntry data = optData.get();
+                () ->  new PluginException("module-info.class not found for " +
+                    module.name() + " module")
+            );
+
             assert module.name().equals(data.moduleName());
             try {
                 ByteArrayInputStream bain = new ByteArrayInputStream(data.contentBytes());
                 ModuleDescriptor md = ModuleDescriptor.read(bain);
                 validateNames(md);
 
-                ModuleDescriptorBuilder mbuilder = builder.module(md, module.packages());
-                int packages = md.exports().size() + md.conceals().size();
-                if (md.conceals().isEmpty() &&
-                        packages != module.packages().size()) {
-                    // add ConcealedPackages attribute if not exist
+                Set<String> packages = module.packages();
+                generator.addModule(md, module.packages());
+
+                // add Packages attribute if not exist
+                if (md.packages().isEmpty() && packages.size() > 0) {
                     bain.reset();
                     ModuleInfoRewriter minfoWriter =
-                        new ModuleInfoRewriter(bain, mbuilder.conceals());
+                        new ModuleInfoRewriter(bain, module.packages());
                     // replace with the overridden version
                     data = data.copyWithContent(minfoWriter.getBytes());
                 }
@@ -149,11 +148,11 @@
         });
 
         // Generate the new class
-        ClassWriter cwriter = builder.build();
+        ClassWriter cwriter = generator.getClassWriter();
         in.entries().forEach(data -> {
             if (data.path().endsWith("module-info.class"))
                 return;
-            if (builder.isOverriddenClass(data.path())) {
+            if (generator.isOverriddenClass(data.path())) {
                 byte[] bytes = cwriter.toByteArray();
                 ResourcePoolEntry ndata = data.copyWithContent(bytes);
                 out.add(ndata);
@@ -166,14 +165,14 @@
     }
 
     /*
-     * Add ConcealedPackages attribute
+     * Add Packages attribute
      */
     class ModuleInfoRewriter extends ByteArrayOutputStream {
         final ModuleInfoExtender extender;
-        ModuleInfoRewriter(InputStream in, Set<String> conceals) throws IOException {
+        ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
             this.extender = ModuleInfoExtender.newExtender(in);
-            // Add ConcealedPackages attribute
-            this.extender.conceals(conceals);
+            // Add Packages attribute
+            this.extender.packages(packages);
             this.extender.write(this);
         }
 
@@ -190,19 +189,21 @@
         for (Exports e : md.exports()) {
             Checks.requirePackageName(e.source());
             if (e.isQualified())
-               e.targets().forEach(Checks::requireModuleName);
+                e.targets().forEach(Checks::requireModuleName);
         }
-        for (Map.Entry<String, Provides> e : md.provides().entrySet()) {
-            String service = e.getKey();
-            Provides provides = e.getValue();
-            Checks.requireServiceTypeName(service);
+        for (Opens opens : md.opens()) {
+            Checks.requirePackageName(opens.source());
+            if (opens.isQualified())
+                opens.targets().forEach(Checks::requireModuleName);
+        }
+        for (Provides provides : md.provides()) {
             Checks.requireServiceTypeName(provides.service());
             provides.providers().forEach(Checks::requireServiceProviderName);
         }
         for (String service : md.uses()) {
             Checks.requireServiceTypeName(service);
         }
-        for (String pn : md.conceals()) {
+        for (String pn : md.packages()) {
             Checks.requirePackageName(pn);
         }
     }
@@ -222,45 +223,60 @@
     }
 
     /**
-     * Builder of a new jdk.internal.module.SystemModules class
-     * to reconstitute ModuleDescriptor of the installed modules.
+     * ClassWriter of a new jdk.internal.module.SystemModules class
+     * to reconstitute ModuleDescriptor of the system modules.
      */
-    static class Builder {
+    static class SystemModulesClassGenerator {
         private static final String CLASSNAME =
             "jdk/internal/module/SystemModules";
         private static final String MODULE_DESCRIPTOR_BUILDER =
             "jdk/internal/module/Builder";
         private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE =
             "[Ljava/lang/module/ModuleDescriptor;";
+        private static final String REQUIRES_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Requires$Modifier";
+        private static final String EXPORTS_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Exports$Modifier";
+        private static final String OPENS_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Opens$Modifier";
 
         // static variables in SystemModules class
         private static final String MODULE_NAMES = "MODULE_NAMES";
         private static final String MODULES_TO_HASH = "MODULES_TO_HASH";
         private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
 
-        private static final int BUILDER_VAR    = 0;
-        private static final int MD_VAR         = 1;   // variable for ModuleDescriptor
-        private static final int MODS_VAR       = 2;   // variable for Set<Modifier>
-        private static final int STRING_SET_VAR = 3;   // variable for Set<String>
         private static final int MAX_LOCAL_VARS = 256;
 
+        private final int BUILDER_VAR    = 0;
+        private final int MD_VAR         = 1;  // variable for ModuleDescriptor
+        private int nextLocalVar         = 2;  // index to next local variable
+
         private final ClassWriter cw;
         private MethodVisitor mv;
-        private int nextLocalVar = 4;
         private int nextModulesIndex = 0;
 
         // list of all ModuleDescriptorBuilders, invoked in turn when building.
         private final List<ModuleDescriptorBuilder> builders = new ArrayList<>();
 
         // module name to hash
-        private final Map<String, String> modulesToHash = new HashMap<>();
+        private final Map<String, byte[]> modulesToHash = new HashMap<>();
+
+        // module name to index in MODULES_TO_HASH
+        private final Map<String, Integer> modulesToHashIndex = new HashMap<>();
 
-        // map Set<String> to a specialized builder to allow them to be
-        // deduplicated as they are requested
-        private final Map<Set<String>, StringSetBuilder> stringSets = new HashMap<>();
+        // A builder to create one single Set instance for a given set of
+        // names or modifiers to reduce the footprint
+        // e.g. target modules of qualified exports
+        private final DedupSetBuilder dedupSetBuilder
+            = new DedupSetBuilder(this::getNextLocalVar);
 
-        public Builder() {
-            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS+ClassWriter.COMPUTE_FRAMES);
+        public SystemModulesClassGenerator() {
+            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
+                                      ClassWriter.COMPUTE_FRAMES);
+        }
+
+        private int getNextLocalVar() {
+            return nextLocalVar++;
         }
 
         /*
@@ -270,16 +286,16 @@
          */
         private void clinit(int numModules, int numPackages) {
             cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
-                    null, "java/lang/Object", null);
+                     null, "java/lang/Object", null);
 
             // public static String[] MODULE_NAMES = new String[] {....};
             cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES,
                     "[Ljava/lang/String;", null, null)
                     .visitEnd();
 
-            // public static String[] MODULES_TO_HASH = new String[] {....};
+            // public static byte[][] MODULES_TO_HASH
             cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULES_TO_HASH,
-                "[Ljava/lang/String;", null, null)
+                "[[B", null, null)
                 .visitEnd();
 
             // public static int PACKAGES_IN_BOOT_LAYER;
@@ -308,23 +324,30 @@
 
             // create the MODULES_TO_HASH array
             pushInt(numModules);
-            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+            mv.visitTypeInsn(ANEWARRAY, "[B");
 
             index = 0;
             for (ModuleDescriptorBuilder builder : builders) {
                 String mn = builder.md.name();
-                String recordedHash = modulesToHash.get(mn);
+                byte[] recordedHash = modulesToHash.get(mn);
                 if (recordedHash != null) {
                     mv.visitInsn(DUP);              // arrayref
                     pushInt(index);
-                    mv.visitLdcInsn(recordedHash);  // value
+                    pushInt(recordedHash.length);
+                    mv.visitIntInsn(NEWARRAY, T_BYTE);
+                    for (int i = 0; i < recordedHash.length; i++) {
+                        mv.visitInsn(DUP);              // arrayref
+                        pushInt(i);
+                        mv.visitIntInsn(BIPUSH, recordedHash[i]);
+                        mv.visitInsn(BASTORE);
+                    }
                     mv.visitInsn(AASTORE);
+                    modulesToHashIndex.put(mn, index);
                 }
                 index++;
             }
 
-            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH,
-                    "[Ljava/lang/String;");
+            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
 
             mv.visitInsn(RETURN);
             mv.visitMaxs(0, 0);
@@ -333,42 +356,42 @@
         }
 
         /*
-         * Adds the given ModuleDescriptor to the installed module list, and
-         * prepares mapping from Set<String> to StringSetBuilders to emit an
-         * optimized number of string sets during build.
+         * Adds the given ModuleDescriptor to the system module list, and
+         * prepares mapping from various Sets to SetBuilders to emit an
+         * optimized number of sets during build.
          */
-        public ModuleDescriptorBuilder module(ModuleDescriptor md, Set<String> packages) {
+        public void addModule(ModuleDescriptor md, Set<String> packages) {
             ModuleDescriptorBuilder builder = new ModuleDescriptorBuilder(md, packages);
             builders.add(builder);
 
             // exports
-            for (ModuleDescriptor.Exports e : md.exports()) {
-                if (e.isQualified()) {
-                    stringSets.computeIfAbsent(e.targets(), s -> new StringSetBuilder(s))
-                              .increment();
-                }
+            for (Exports e : md.exports()) {
+                dedupSetBuilder.stringSet(e.targets());
+                dedupSetBuilder.exportsModifiers(e.modifiers());
             }
 
-            // provides (preserve iteration order)
-            for (ModuleDescriptor.Provides p : md.provides().values()) {
-                stringSets.computeIfAbsent(p.providers(), s -> new StringSetBuilder(s, true))
-                          .increment();
+            // opens
+            for (Opens opens : md.opens()) {
+                dedupSetBuilder.stringSet(opens.targets());
+                dedupSetBuilder.opensModifiers(opens.modifiers());
+            }
+
+            // requires
+            for (Requires r : md.requires()) {
+                dedupSetBuilder.requiresModifiers(r.modifiers());
             }
 
             // uses
-            stringSets.computeIfAbsent(md.uses(), s -> new StringSetBuilder(s))
-                      .increment();
+            dedupSetBuilder.stringSet(md.uses());
 
             // hashes
             JLMA.hashes(md).ifPresent(mh -> modulesToHash.putAll(mh.hashes()));
-
-            return builder;
         }
 
         /*
          * Generate bytecode for SystemModules
          */
-        public ClassWriter build() {
+        public ClassWriter getClassWriter() {
             int numModules = builders.size();
             int numPackages = 0;
             for (ModuleDescriptorBuilder builder : builders) {
@@ -411,108 +434,79 @@
         }
 
         class ModuleDescriptorBuilder {
-            static final String REQUIRES_MODIFIER_CLASSNAME =
-                    "java/lang/module/ModuleDescriptor$Requires$Modifier";
-            static final String REQUIRES_MODIFIER_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Requires$Modifier;";
             static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
-            static final String REQUIRES_MODIFIER_STRING_SIG =
-                "(" + REQUIRES_MODIFIER_TYPE + "Ljava/lang/String;)" + BUILDER_TYPE;
-            static final String STRING_SET_SIG =
-                "(Ljava/lang/String;Ljava/util/Set;)" + BUILDER_TYPE;
-            static final String SET_STRING_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;)" + BUILDER_TYPE;
-            static final String SET_SIG =
-                "(Ljava/util/Set;)" + BUILDER_TYPE;
+            static final String EXPORTS_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Exports;";
+            static final String OPENS_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Opens;";
+            static final String PROVIDES_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Provides;";
+            static final String REQUIRES_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Requires;";
+
+            // method signature for static Builder::newExports, newOpens,
+            // newProvides, newRequires methods
+            static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
+                    + EXPORTS_TYPE;
+            static final String EXPORTS_MODIFIER_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE;
+            static final String OPENS_MODIFIER_SET_STRING_SET_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
+                    + OPENS_TYPE;
+            static final String OPENS_MODIFIER_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE;
+            static final String PROVIDES_STRING_LIST_SIG =
+                "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE;
+            static final String REQUIRES_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE;
+
+            // method signature for Builder instance methods that
+            // return this Builder instance
+            static final String EXPORTS_ARRAY_SIG =
+                "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE;
+            static final String OPENS_ARRAY_SIG =
+                "([" + OPENS_TYPE + ")" + BUILDER_TYPE;
+            static final String PROVIDES_ARRAY_SIG =
+                "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE;
+            static final String REQUIRES_ARRAY_SIG =
+                "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE;
+            static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE;
             static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
-            static final String STRING_STRING_SIG =
-                "(Ljava/lang/String;Ljava/lang/String;)" + BUILDER_TYPE;
+            static final String STRING_BYTE_ARRAY_SIG =
+                "(Ljava/lang/String;[B)" + BUILDER_TYPE;
+            static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE;
+
 
             final ModuleDescriptor md;
             final Set<String> packages;
 
             ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages) {
+                if (md.isAutomatic()) {
+                    throw new InternalError("linking automatic module is not supported");
+                }
                 this.md = md;
                 this.packages = packages;
             }
 
-            void newBuilder(String name, int reqs, int exports, int provides,
-                            int packages) {
-                mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
-                mv.visitInsn(DUP);
-                mv.visitLdcInsn(name);
-                pushInt(initialCapacity(reqs));
-                pushInt(initialCapacity(exports));
-                pushInt(initialCapacity(provides));
-                pushInt(initialCapacity(packages));
-                mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "<init>", "(Ljava/lang/String;IIII)V", false);
-                mv.visitVarInsn(ASTORE, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-            }
-
-            /*
-             * Returns the set of concealed packages from ModuleDescriptor, if present
-             * or compute it if the module does not have ConcealedPackages attribute
-             */
-            Set<String> conceals() {
-                Set<String> conceals = md.conceals();
-                if (conceals.isEmpty() && md.exports().size() != packages.size()) {
-                    Set<String> exports = md.exports().stream()
-                                            .map(Exports::source)
-                                            .collect(Collectors.toSet());
-                    conceals = packages.stream()
-                                       .filter(pn -> !exports.contains(pn))
-                                       .collect(Collectors.toSet());
-                }
-
-                if (conceals.size() + md.exports().size() != packages.size() &&
-                    // jdk.localedata may have concealed packages that don't exist
-                    !md.name().equals("jdk.localedata")) {
-                    throw new AssertionError(md.name() + ": conceals=" + conceals.size() +
-                            ", exports=" + md.exports().size() + ", packages=" + packages.size());
-                }
-                return conceals;
-            }
-
             void build() {
-                newBuilder(md.name(), md.requires().size(),
-                           md.exports().size(),
-                           md.provides().size(),
-                           packages.size());
+                // new jdk.internal.module.Builder
+                newBuilder();
 
                 // requires
-                for (ModuleDescriptor.Requires req : md.requires()) {
-                    switch (req.modifiers().size()) {
-                        case 0:
-                            requires(req.name());
-                            break;
-                        case 1:
-                            ModuleDescriptor.Requires.Modifier mod =
-                                req.modifiers().iterator().next();
-                            requires(mod, req.name());
-                            break;
-                        default:
-                            requires(req.modifiers(), req.name());
-                    }
-                }
+                requires(md.requires());
 
                 // exports
-                for (ModuleDescriptor.Exports e : md.exports()) {
-                    if (e.isQualified()) {
-                        exports(e.source(), e.targets());
-                    } else {
-                        exports(e.source());
-                    }
-                }
+                exports(md.exports());
+
+                // opens
+                opens(md.opens());
 
                 // uses
                 uses(md.uses());
 
                 // provides
-                for (ModuleDescriptor.Provides p : md.provides().values()) {
-                    provides(p.service(), p.providers());
-                }
+                provides(md.provides());
 
                 // all packages
                 packages(packages);
@@ -532,6 +526,38 @@
                 putModuleDescriptor();
             }
 
+            void newBuilder() {
+                mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
+                mv.visitInsn(DUP);
+                mv.visitLdcInsn(md.name());
+                mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
+                    "<init>", "(Ljava/lang/String;)V", false);
+                mv.visitVarInsn(ASTORE, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+
+                if (md.isOpen()) {
+                    setModuleBit("open", true);
+                }
+                if (md.isSynthetic()) {
+                    setModuleBit("synthetic", true);
+                }
+            }
+
+            /*
+             * Invoke Builder.<methodName>(boolean value)
+             */
+            void setModuleBit(String methodName, boolean value) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                if (value) {
+                    mv.visitInsn(ICONST_1);
+                } else {
+                    mv.visitInsn(ICONST_0);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   methodName, BOOLEAN_SIG, false);
+                mv.visitInsn(POP);
+            }
+
             /*
              * Put ModuleDescriptor into the modules array
              */
@@ -539,130 +565,220 @@
                 mv.visitVarInsn(ALOAD, MD_VAR);
                 pushInt(nextModulesIndex++);
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(md.hashCode());
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                    "build", "()Ljava/lang/module/ModuleDescriptor;", false);
+                                   "build", "(I)Ljava/lang/module/ModuleDescriptor;",
+                                   false);
                 mv.visitInsn(AASTORE);
             }
 
             /*
-             * Invoke Builder.requires(String mn)
+             * Call Builder::newRequires to create Requires instances and
+             * then pass it to the builder by calling:
+             *      Builder.requires(Requires[])
+             *
              */
-            void requires(String name) {
+            void requires(Set<Requires> requires) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(name);
+                pushInt(requires.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires");
+                int arrayIndex = 0;
+                for (Requires require : requires) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(arrayIndex++);
+                    newRequires(require.modifiers(), require.name());
+                    mv.visitInsn(AASTORE);
+                }
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "requires", STRING_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.requires(Modifier mod, String mn)
-             */
-            void requires(ModuleDescriptor.Requires.Modifier mod, String name) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitFieldInsn(GETSTATIC, REQUIRES_MODIFIER_CLASSNAME, mod.name(),
-                                  REQUIRES_MODIFIER_TYPE);
-                mv.visitLdcInsn(name);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "requires", REQUIRES_MODIFIER_STRING_SIG, false);
-                mv.visitInsn(POP);
+                                   "requires", REQUIRES_ARRAY_SIG, false);
             }
 
             /*
-             * Invoke Builder.requires(Set<Modifier> mods, String mn)
+             * Invoke Builder.newRequires(Set<Modifier> mods, String mn)
              *
-             * EnumSet<Modifier> mods = EnumSet.of(mod,....);
-             * Buidler.requires(mods, mn);
+             * Set<Modifier> mods = ...
+             * Builder.newRequires(mods, mn);
              */
-            void requires(Set<ModuleDescriptor.Requires.Modifier> mods, String name) {
-                mv.visitVarInsn(ALOAD, MODS_VAR);
-                String signature = "(";
-                for (ModuleDescriptor.Requires.Modifier m : mods) {
-                    mv.visitFieldInsn(GETSTATIC, REQUIRES_MODIFIER_CLASSNAME, m.name(),
-                                      REQUIRES_MODIFIER_TYPE);
-                    signature += "Ljava/util/Enum;";
-                }
-                signature += ")Ljava/util/EnumSet;";
-                mv.visitMethodInsn(INVOKESTATIC, "java/util/EnumSet", "of",
-                                   signature, false);
-                mv.visitVarInsn(ASTORE, MODS_VAR);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, MODS_VAR);
+            void newRequires(Set<Requires.Modifier> mods, String name) {
+                int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
+                mv.visitVarInsn(ALOAD, varIndex);
                 mv.visitLdcInsn(name);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "requires", SET_STRING_SIG, false);
-                mv.visitInsn(POP);
+                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                                   "newRequires", REQUIRES_SET_STRING_SIG, false);
             }
 
             /*
-             * Invoke Builder.exports(String pn)
+             * Call Builder::newExports to create Exports instances and
+             * then pass it to the builder by calling:
+             *      Builder.exports(Exports[])
+             *
              */
-            void exports(String pn) {
+            void exports(Set<Exports> exports) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
-
-                mv.visitLdcInsn(pn);
+                pushInt(exports.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports");
+                int arrayIndex = 0;
+                for (Exports export : exports) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(arrayIndex++);
+                    newExports(export.modifiers(), export.source(), export.targets());
+                    mv.visitInsn(AASTORE);
+                }
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                        "exports", STRING_SIG, false);
-                mv.visitInsn(POP);
+                                   "exports", EXPORTS_ARRAY_SIG, false);
             }
 
             /*
-             * Invoke Builder.exports(String pn, Set<String> targets)
+             * Invoke
+             *     Builder.newExports(Set<Exports.Modifier> ms, String pn,
+             *                        Set<String> targets)
+             * or
+             *     Builder.newExports(Set<Exports.Modifier> ms, String pn)
              *
              * Set<String> targets = new HashSet<>();
              * targets.add(t);
              * :
              * :
-             * Builder.exports(pn, targets);
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newExports(mods, pn, targets);
              */
-            void exports(String pn, Set<String> targets) {
-                int varIndex = stringSets.get(targets).build();
+            void newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets) {
+                int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms);
+                if (!targets.isEmpty()) {
+                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitVarInsn(ALOAD, stringSetIndex);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false);
+                } else {
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false);
+                }
+            }
+
+
+            /**
+             * Call Builder::newOpens to create Opens instances and
+             * then pass it to the builder by calling:
+             *      Builder.opens(Opens[])
+             *
+             */
+            void opens(Set<Opens> opens) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(pn);
-                mv.visitVarInsn(ALOAD, varIndex);
+                pushInt(opens.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens");
+                int arrayIndex = 0;
+                for (Opens open : opens) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(arrayIndex++);
+                    newOpens(open.modifiers(), open.source(), open.targets());
+                    mv.visitInsn(AASTORE);
+                }
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "exports", STRING_SET_SIG, false);
-                mv.visitInsn(POP);
+                        "opens", OPENS_ARRAY_SIG, false);
             }
 
             /*
-             * Invokes Builder.uses(Set<String> uses)
+             * Invoke
+             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn,
+             *                        Set<String> targets)
+             * or
+             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn)
+             *
+             * Set<String> targets = new HashSet<>();
+             * targets.add(t);
+             * :
+             * :
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newOpens(mods, pn, targets);
+             */
+            void newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets) {
+                int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms);
+                if (!targets.isEmpty()) {
+                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitVarInsn(ALOAD, stringSetIndex);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                            "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
+                } else {
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                            "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
+                }
+            }
+
+            /*
+             * Invoke Builder.uses(Set<String> uses)
              */
             void uses(Set<String> uses) {
-                int varIndex = stringSets.get(uses).build();
+                int varIndex = dedupSetBuilder.indexOfStringSet(uses);
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
                 mv.visitVarInsn(ALOAD, varIndex);
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                        "uses", SET_SIG, false);
+                                   "uses", SET_SIG, false);
                 mv.visitInsn(POP);
             }
 
             /*
-             * Invoke Builder.provides(String service, Set<String> providers)
+            * Call Builder::newProvides to create Provides instances and
+            * then pass it to the builder by calling:
+            *      Builder.provides(Provides[] provides)
+            *
+            */
+            void provides(Collection<Provides> provides) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(provides.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides");
+                int arrayIndex = 0;
+                for (Provides provide : provides) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(arrayIndex++);
+                    newProvides(provide.service(), provide.providers());
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                                   "provides", PROVIDES_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke Builder.newProvides(String service, Set<String> providers)
              *
-             * Set<String> providers = new LinkedHashSet<>();
+             * Set<String> providers = new HashSet<>();
              * providers.add(impl);
              * :
              * :
-             * Builder.exports(service, providers);
+             * Builder.newProvides(service, providers);
              */
-            void provides(String service, Set<String> providers) {
-                int varIndex = stringSets.get(providers).build();
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+            void newProvides(String service, List<String> providers) {
                 mv.visitLdcInsn(service);
-                mv.visitVarInsn(ALOAD, varIndex);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "provides", STRING_SET_SIG, false);
-                mv.visitInsn(POP);
+                pushInt(providers.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+                int arrayIndex = 0;
+                for (String provider : providers) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(arrayIndex++);
+                    mv.visitLdcInsn(provider);
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKESTATIC, "java/util/List",
+                                   "of", "([Ljava/lang/Object;)Ljava/util/List;", true);
+                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                                   "newProvides", PROVIDES_STRING_LIST_SIG, false);
             }
 
             /*
-             * Invoke Builder.conceals(String pn)
+             * Invoke Builder.packages(String pn)
              */
             void packages(Set<String> packages) {
+                int varIndex = dedupSetBuilder.newStringSet(packages);
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                int varIndex = new StringSetBuilder(packages).build();
-                assert varIndex == STRING_SET_VAR;
                 mv.visitVarInsn(ALOAD, varIndex);
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
                                    "packages", SET_SIG, false);
@@ -683,7 +799,7 @@
             /*
              * Invoke Builder.version(Version v);
              */
-            void version(ModuleDescriptor.Version v) {
+            void version(Version v) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
                 mv.visitLdcInsn(v.toString());
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
@@ -691,99 +807,277 @@
                 mv.visitInsn(POP);
             }
 
+            /*
+             * Invoke Builder.algorithm(String a);
+             */
             void algorithm(String alg) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
                 mv.visitLdcInsn(alg);
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                    "algorithm", STRING_SIG, false);
+                                   "algorithm", STRING_SIG, false);
                 mv.visitInsn(POP);
             }
 
-            void moduleHash(String name, String hashString) {
+            /*
+             * Invoke Builder.moduleHash(String name, byte[] hash);
+             */
+            void moduleHash(String name, byte[] hash) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
                 mv.visitLdcInsn(name);
-                mv.visitLdcInsn(hashString);
+
+                // must exist
+                Integer index = modulesToHashIndex.get(name);
+                if (index != null) {
+                    mv.visitFieldInsn(GETSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
+                    pushInt(index);
+                    mv.visitInsn(AALOAD);
+                    assert(Objects.equals(hash, modulesToHash.get(name)));
+                } else {
+                    pushInt(hash.length);
+                    mv.visitIntInsn(NEWARRAY, T_BYTE);
+                    for (int i = 0; i < hash.length; i++) {
+                        mv.visitInsn(DUP);              // arrayref
+                        pushInt(i);
+                        mv.visitIntInsn(BIPUSH, hash[i]);
+                        mv.visitInsn(BASTORE);
+                    }
+                }
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                    "moduleHash", STRING_STRING_SIG, false);
+                                   "moduleHash", STRING_BYTE_ARRAY_SIG, false);
                 mv.visitInsn(POP);
             }
         }
 
         /*
-         * StringSetBuilder generates bytecode to create one single instance
-         * of HashSet for a given set of names and assign to a local variable
-         * slot.  When there is only one single reference to a Set<String>,
-         * it will reuse STRING_SET_VAR for reference.  For Set<String> with
-         * multiple references, it will use a new local variable.
+         * Wraps set creation, ensuring identical sets are properly deduplicated.
          */
-        class StringSetBuilder {
-            final Set<String> names;
-            final boolean linked;
-            int refCount;
-            int localVarIndex;
+        class DedupSetBuilder {
+            // map Set<String> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<String>, SetBuilder<String>> stringSets = new HashMap<>();
+
+            // map Set<Requires.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Requires.Modifier>, EnumSetBuilder<Requires.Modifier>>
+                requiresModifiersSets = new HashMap<>();
+
+            // map Set<Exports.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Exports.Modifier>, EnumSetBuilder<Exports.Modifier>>
+                exportsModifiersSets = new HashMap<>();
+
+            // map Set<Opens.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Opens.Modifier>, EnumSetBuilder<Opens.Modifier>>
+                opensModifiersSets = new HashMap<>();
+
+            private final int stringSetVar;
+            private final int enumSetVar;
+            private final IntSupplier localVarSupplier;
 
-            StringSetBuilder(Set<String> names, boolean linked) {
-                this.names = names;
-                this.linked = linked;
+            DedupSetBuilder(IntSupplier localVarSupplier) {
+                this.stringSetVar = localVarSupplier.getAsInt();
+                this.enumSetVar = localVarSupplier.getAsInt();
+                this.localVarSupplier = localVarSupplier;
+            }
+
+            /*
+             * Add the given set of strings to this builder.
+             */
+            void stringSet(Set<String> strings) {
+                stringSets.computeIfAbsent(strings,
+                    s -> new SetBuilder<>(s, stringSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Add the given set of Exports.Modifiers
+             */
+            void exportsModifiers(Set<Exports.Modifier> mods) {
+                exportsModifiersSets.computeIfAbsent(mods, s ->
+                                new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME,
+                                        enumSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Add the given set of Opens.Modifiers
+             */
+            void opensModifiers(Set<Opens.Modifier> mods) {
+                opensModifiersSets.computeIfAbsent(mods, s ->
+                                new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME,
+                                        enumSetVar, localVarSupplier)
+                ).increment();
             }
 
-            StringSetBuilder(Set<String> names) {
-                this(names, false);
+            /*
+             * Add the given set of Requires.Modifiers
+             */
+            void requiresModifiers(Set<Requires.Modifier> mods) {
+                requiresModifiersSets.computeIfAbsent(mods, s ->
+                    new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME,
+                                         enumSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Retrieve the index to the given set of Strings. Emit code to
+             * generate it when SetBuilder::build is called.
+             */
+            int indexOfStringSet(Set<String> names) {
+                return stringSets.get(names).build();
+            }
+
+            /*
+             * Retrieve the index to the given set of Exports.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfExportsModifiers(Set<Exports.Modifier> mods) {
+                return exportsModifiersSets.get(mods).build();
+            }
+
+            /**
+             * Retrieve the index to the given set of Opens.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfOpensModifiers(Set<Opens.Modifier> mods) {
+                return opensModifiersSets.get(mods).build();
             }
 
-            void increment() {
+
+            /*
+             * Retrieve the index to the given set of Requires.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfRequiresModifiers(Set<Requires.Modifier> mods) {
+                return requiresModifiersSets.get(mods).build();
+            }
+
+            /*
+             * Build a new string set without any attempt to deduplicate it.
+             */
+            int newStringSet(Set<String> names) {
+                int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build();
+                assert index == stringSetVar;
+                return index;
+            }
+        }
+
+        /*
+         * SetBuilder generates bytecode to create one single instance of Set
+         * for a given set of elements and assign to a local variable slot.
+         * When there is only one single reference to a Set<T>,
+         * it will reuse defaultVarIndex.  For a Set with multiple references,
+         * it will use a new local variable retrieved from the nextLocalVar
+         */
+        class SetBuilder<T> {
+            private final Set<T> elements;
+            private final int defaultVarIndex;
+            private final IntSupplier nextLocalVar;
+            private int refCount;
+            private int localVarIndex;
+
+            SetBuilder(Set<T> elements,
+                       int defaultVarIndex,
+                       IntSupplier nextLocalVar) {
+                this.elements = elements;
+                this.defaultVarIndex = defaultVarIndex;
+                this.nextLocalVar = nextLocalVar;
+            }
+
+            /*
+             * Increments the number of references to this particular set.
+             */
+            final void increment() {
                 refCount++;
             }
 
+            /**
+             * Generate the appropriate instructions to load an object reference
+             * to the element onto the stack.
+             */
+            void visitElement(T element, MethodVisitor mv) {
+                mv.visitLdcInsn(element);
+            }
+
             /*
-             * Build bytecode for the Set<String> represented by this builder,
+             * Build bytecode for the Set represented by this builder,
              * or get the local variable index of a previously generated set
              * (in the local scope).
              *
              * @return local variable index of the generated set.
              */
-            int build() {
+            final int build() {
                 int index = localVarIndex;
                 if (localVarIndex == 0) {
                     // if non-empty and more than one set reference this builder,
                     // emit to a unique local
-                    index = refCount <= 1 ? STRING_SET_VAR
-                                          : nextLocalVar++;
+                    index = refCount <= 1 ? defaultVarIndex
+                                          : nextLocalVar.getAsInt();
                     if (index < MAX_LOCAL_VARS) {
                         localVarIndex = index;
                     } else {
-                        // overflow: disable optimization and keep localVarIndex = 0
-                        index = STRING_SET_VAR;
+                        // overflow: disable optimization by using localVarIndex = 0
+                        index = defaultVarIndex;
                     }
 
-                    if (names.isEmpty()) {
-                        mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections",
-                                "emptySet", "()Ljava/util/Set;", false);
-                        mv.visitVarInsn(ASTORE, index);
-                    } else if (names.size() == 1) {
-                        mv.visitLdcInsn(names.iterator().next());
-                        mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections",
-                                "singleton", "(Ljava/lang/Object;)Ljava/util/Set;", false);
-                        mv.visitVarInsn(ASTORE, index);
-                    } else {
-                        String cn = linked ? "java/util/LinkedHashSet" : "java/util/HashSet";
-                        mv.visitTypeInsn(NEW, cn);
-                        mv.visitInsn(DUP);
-                        pushInt(initialCapacity(names.size()));
-                        mv.visitMethodInsn(INVOKESPECIAL, cn, "<init>", "(I)V", false);
-
-                        mv.visitVarInsn(ASTORE, index);
-                        for (String t : names) {
-                            mv.visitVarInsn(ALOAD, index);
-                            mv.visitLdcInsn(t);
-                            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set",
-                                    "add", "(Ljava/lang/Object;)Z", true);
-                            mv.visitInsn(POP);
-                        }
-                    }
+                    generateSetOf(index);
                 }
                 return index;
             }
+
+            private void generateSetOf(int index) {
+                if (elements.size() <= 10) {
+                    // call Set.of(e1, e2, ...)
+                    StringBuilder sb = new StringBuilder("(");
+                    for (T t : elements) {
+                        sb.append("Ljava/lang/Object;");
+                        visitElement(t, mv);
+                    }
+                    sb.append(")Ljava/util/Set;");
+                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
+                            "of", sb.toString(), true);
+                } else {
+                    // call Set.of(E... elements)
+                    pushInt(elements.size());
+                    mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+                    int arrayIndex = 0;
+                    for (T t : elements) {
+                        mv.visitInsn(DUP);    // arrayref
+                        pushInt(arrayIndex);
+                        visitElement(t, mv);  // value
+                        mv.visitInsn(AASTORE);
+                        arrayIndex++;
+                    }
+                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
+                            "of", "([Ljava/lang/Object;)Ljava/util/Set;", true);
+                }
+                mv.visitVarInsn(ASTORE, index);
+            }
+        }
+
+        /*
+         * Generates bytecode to create one single instance of EnumSet
+         * for a given set of modifiers and assign to a local variable slot.
+         */
+        class EnumSetBuilder<T> extends SetBuilder<T> {
+
+            private final String className;
+
+            EnumSetBuilder(Set<T> modifiers, String className,
+                           int defaultVarIndex,
+                           IntSupplier nextLocalVar) {
+                super(modifiers, defaultVarIndex, nextLocalVar);
+                this.className = className;
+            }
+
+            /**
+             * Loads an Enum field.
+             */
+            void visitElement(T t, MethodVisitor mv) {
+                mv.visitFieldInsn(GETSTATIC, className, t.toString(),
+                                  "L" + className + ";");
+            }
         }
     }
 }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -80,7 +80,7 @@
 Takes a file hinting to jlink what java.lang.invoke classes to pre-generate. If\n\
 this flag is not specified a default set of classes will be generated.
 
-installed-modules.description=Fast loading of module descriptors (always enabled)
+system-modules.description=Fast loading of module descriptors (always enabled)
 
 onoff.argument=<on|off>
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Wed Jul 05 22:32:06 2017 +0200
@@ -40,6 +40,7 @@
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Version;
@@ -83,6 +84,7 @@
 import java.util.stream.Collectors;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
+import java.util.stream.Stream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
@@ -97,6 +99,7 @@
 import jdk.internal.joptsimple.OptionSet;
 import jdk.internal.joptsimple.OptionSpec;
 import jdk.internal.joptsimple.ValueConverter;
+import jdk.internal.loader.ResourceHelper;
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ModuleHashes;
@@ -261,9 +264,9 @@
         }
     }
 
-    static <T> String toString(Set<T> set) {
-        if (set.isEmpty()) { return ""; }
-        return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
+    static <T> String toString(Collection<T> c) {
+        if (c.isEmpty()) { return ""; }
+        return c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
                   .collect(joining(" "));
     }
 
@@ -291,14 +294,21 @@
             .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.opens().stream()
+            .sorted(Comparator.comparing(Opens::source))
+            .forEach(p -> sb.append("\n  opens ").append(p));
 
-        md.provides().values().stream()
+        Set<String> concealed = new HashSet<>(md.packages());
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        md.opens().stream().map(Opens::source).forEach(concealed::remove);
+        concealed.stream().sorted()
+                 .forEach(p -> sb.append("\n  contains ").append(p));
+
+        md.provides().stream()
             .sorted(Comparator.comparing(Provides::service))
             .forEach(p -> sb.append("\n  provides ").append(p.service())
-                .append(" with ")
-                .append(toString(p.providers())));
+                            .append(" with ")
+                            .append(toString(p.providers())));
 
         md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
 
@@ -311,8 +321,8 @@
         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))));
+                         .append(hashes.algorithm()).append(" ")
+                         .append(hashes.hashFor(mod))));
 
         out.println(sb.toString());
     }
@@ -414,7 +424,7 @@
         /**
          * Writes the updated module-info.class to the ZIP output stream.
          *
-         * The updated module-info.class will have a ConcealedPackages attribute
+         * The updated module-info.class will have a Packages attribute
          * with the set of module-private/non-exported packages.
          *
          * If --module-version, --main-class, or other options were provided
@@ -439,15 +449,9 @@
             try (InputStream in = miSupplier.get()) {
                 ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
 
-                // Add (or replace) the ConcealedPackages attribute
+                // Add (or replace) the Packages attribute
                 if (packages != null) {
-                    Set<String> exported = descriptor.exports().stream()
-                        .map(ModuleDescriptor.Exports::source)
-                        .collect(Collectors.toSet());
-                    Set<String> concealed = packages.stream()
-                        .filter(p -> !exported.contains(p))
-                        .collect(Collectors.toSet());
-                    extender.conceals(concealed);
+                    extender.packages(packages);
                 }
 
                 // --main-class
@@ -556,10 +560,11 @@
         Set<String> findPackages(Path dir) {
             try {
                 return Files.find(dir, Integer.MAX_VALUE,
-                        ((path, attrs) -> attrs.isRegularFile() &&
-                                path.toString().endsWith(".class")))
-                        .map(path -> toPackageName(dir.relativize(path)))
-                        .filter(pkg -> pkg.length() > 0)   // module-info
+                                  ((path, attrs) -> attrs.isRegularFile()))
+                        .map(dir::relativize)
+                        .filter(path -> isResource(path.toString()))
+                        .map(path -> toPackageName(path))
+                        .filter(pkg -> pkg.length() > 0)
                         .distinct()
                         .collect(Collectors.toSet());
             } catch (IOException ioe) {
@@ -572,21 +577,30 @@
          */
         Set<String> findPackages(JarFile jf) {
             return jf.stream()
-                     .filter(e -> e.getName().endsWith(".class"))
+                     .filter(e -> !e.isDirectory() && isResource(e.getName()))
                      .map(e -> toPackageName(e))
-                     .filter(pkg -> pkg.length() > 0)   // module-info
+                     .filter(pkg -> pkg.length() > 0)
                      .distinct()
                      .collect(Collectors.toSet());
         }
 
+        /**
+         * Returns true if it's a .class or a resource with an effective
+         * package name.
+         */
+        boolean isResource(String name) {
+            name = name.replace(File.separatorChar, '/');
+            return name.endsWith(".class") || !ResourceHelper.isSimpleResource(name);
+        }
+
+
         String toPackageName(Path path) {
             String name = path.toString();
-            assert name.endsWith(".class");
             int index = name.lastIndexOf(File.separatorChar);
             if (index != -1)
                 return name.substring(0, index).replace(File.separatorChar, '.');
 
-            if (!name.equals(MODULE_INFO)) {
+            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
                 IOException e = new IOException(name  + " in the unnamed package");
                 throw new UncheckedIOException(e);
             }
@@ -595,12 +609,15 @@
 
         String toPackageName(ZipEntry entry) {
             String name = entry.getName();
-            assert name.endsWith(".class");
             int index = name.lastIndexOf("/");
             if (index != -1)
                 return name.substring(0, index).replace('/', '.');
-            else
-                return "";
+
+            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+                IOException e = new IOException(name  + " in the unnamed package");
+                throw new UncheckedIOException(e);
+            }
+            return "";
         }
 
         void processClasses(JmodOutputStream out, List<Path> classpaths)
--- a/jdk/src/jdk.jlink/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jlink/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -31,21 +31,23 @@
 
     uses jdk.tools.jlink.plugin.Plugin;
 
-    provides java.util.spi.ToolProvider with jdk.tools.jmod.Main.JmodToolProvider;
-    provides java.util.spi.ToolProvider with jdk.tools.jlink.internal.Main.JlinkToolProvider;
+    provides java.util.spi.ToolProvider with
+        jdk.tools.jmod.Main.JmodToolProvider,
+        jdk.tools.jlink.internal.Main.JlinkToolProvider;
 
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.FileCopierPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.StripDebugPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludePlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.OrderResourcesPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeVMPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ClassForNamePlugin;
+    provides jdk.tools.jlink.plugin.Plugin with
+        jdk.tools.jlink.internal.plugins.FileCopierPlugin,
+        jdk.tools.jlink.internal.plugins.StripDebugPlugin,
+        jdk.tools.jlink.internal.plugins.ExcludePlugin,
+        jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin,
+        jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin,
+        jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin,
+        jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin,
+        jdk.tools.jlink.internal.plugins.OrderResourcesPlugin,
+        jdk.tools.jlink.internal.plugins.DefaultCompressPlugin,
+        jdk.tools.jlink.internal.plugins.ExcludeVMPlugin,
+        jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin,
+        jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin,
+        jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin,
+        jdk.tools.jlink.internal.plugins.ClassForNamePlugin;
  }
--- a/jdk/src/jdk.jvmstat/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.jvmstat/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -36,7 +36,8 @@
         jdk.jstatd;
 
     uses sun.jvmstat.monitor.MonitoredHostService;
-    provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService;
-    provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService;
+    provides sun.jvmstat.monitor.MonitoredHostService with
+        sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService,
+        sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService;
 }
 
--- a/jdk/src/jdk.localedata/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.localedata/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,8 +25,7 @@
 
 module jdk.localedata {
     provides sun.util.locale.provider.LocaleDataMetaInfo with
-        sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo;
-    provides sun.util.locale.provider.LocaleDataMetaInfo with
+        sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo,
         sun.util.resources.provider.NonBaseLocaleDataMetaInfo;
     provides sun.util.resources.LocaleData.CommonResourceBundleProvider with
         sun.util.resources.provider.LocaleDataProvider;
--- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_sr_Latn.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_sr_Latn.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -167,8 +167,8 @@
             },
             { "NumberElements",
                 new String[] {
+                    ",",
                     ".",
-                    ",",
                     ";",
                     "%",
                     "0",
--- a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_sv.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_sv.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -270,6 +270,13 @@
                     "e",
                 }
             },
+            { "NumberPatterns",
+                new String[] {
+                    "#,##0.###;-#,##0.###", // decimal pattern
+                    "\u00a4 #,##0.00;-\u00a4 #,##0.00", // currency pattern
+                    "#,##0 %" // percent pattern
+                }
+            },
             { "NumberElements",
                 new String[] {
                     ",", // decimal separator
--- a/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java	Wed Jul 05 22:32:06 2017 +0200
@@ -238,9 +238,4 @@
         }
 
     }
-
-    // for sun.management.MappedMXBeanType
-    static CompositeData toCompositeData(VMOption option) {
-        return VMOptionCompositeData.toCompositeData(option);
-    }
 }
--- a/jdk/src/jdk.management/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.management/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,7 @@
  */
 
 module jdk.management {
-    requires public java.management;
+    requires transitive java.management;
 
     exports com.sun.management;
 
--- a/jdk/src/jdk.naming.dns/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.naming.dns/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,8 +26,8 @@
 module jdk.naming.dns {
     requires java.naming;
 
-    exports com.sun.jndi.url.dns to
-        java.naming;
+    // temporary export until NamingManager.getURLContext uses services
+    exports com.sun.jndi.url.dns to java.naming;
 
     provides javax.naming.spi.InitialContextFactory
         with com.sun.jndi.dns.DnsContextFactory;
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java	Wed Jul 05 22:32:06 2017 +0200
@@ -54,14 +54,7 @@
     private static final long serialVersionUID = 2345199581042573224L;
 
     private static final java.util.ResourceBundle rb =
-          java.security.AccessController.doPrivileged
-          (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
-              public java.util.ResourceBundle run() {
-                  return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources",
-                                sun.security.util.ResourcesMgr.class.getModule()));
-              }
-          });
+        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /**
      * @serial
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java	Wed Jul 05 22:32:06 2017 +0200
@@ -53,15 +53,7 @@
     private static final long serialVersionUID = -3178578484679887104L;
 
     private static final java.util.ResourceBundle rb =
-          java.security.AccessController.doPrivileged
-          (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
-              public java.util.ResourceBundle run() {
-                  return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources",
-                                 sun.security.util.ResourcesMgr.class.getModule()));
-              }
-           });
-
+        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /**
      * @serial
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java	Wed Jul 05 22:32:06 2017 +0200
@@ -51,14 +51,7 @@
     private static final long serialVersionUID = -7840670002439379038L;
 
     private static final java.util.ResourceBundle rb =
-          java.security.AccessController.doPrivileged
-          (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
-              public java.util.ResourceBundle run() {
-                  return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources",
-                                 sun.security.util.ResourcesMgr.class.getModule()));
-              }
-          });
+        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
 
 
     /**
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java	Wed Jul 05 22:32:06 2017 +0200
@@ -56,14 +56,7 @@
     private static final long serialVersionUID = -8222422609431628648L;
 
     private static final java.util.ResourceBundle rb =
-        java.security.AccessController.doPrivileged
-        (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
-              public java.util.ResourceBundle run() {
-                  return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources",
-                                 sun.security.util.ResourcesMgr.class.getModule()));
-              }
-        });
+        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /**
      * @serial
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java	Wed Jul 05 22:32:06 2017 +0200
@@ -153,15 +153,8 @@
  */
 public class JndiLoginModule implements LoginModule {
 
-    private static final ResourceBundle rb = AccessController.doPrivileged(
-            new PrivilegedAction<ResourceBundle>() {
-                public ResourceBundle run() {
-                    return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources",
-                            sun.security.util.ResourcesMgr.class.getModule());
-                }
-            }
-    );
+    private static final ResourceBundle rb =
+        ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /** JNDI Provider */
     public final String USER_PROVIDER = "user.provider.url";
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java	Wed Jul 05 22:32:06 2017 +0200
@@ -112,15 +112,8 @@
  */
 public class KeyStoreLoginModule implements LoginModule {
 
-    private static final ResourceBundle rb = AccessController.doPrivileged(
-            new PrivilegedAction<ResourceBundle>() {
-                public ResourceBundle run() {
-                    return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources",
-                            sun.security.util.ResourcesMgr.class.getModule());
-                }
-            }
-    );
+    private static final ResourceBundle rb =
+        ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /* -- Fields -- */
 
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java	Wed Jul 05 22:32:06 2017 +0200
@@ -419,15 +419,8 @@
 
     private static final String NAME = "javax.security.auth.login.name";
     private static final String PWD = "javax.security.auth.login.password";
-    private static final ResourceBundle rb = AccessController.doPrivileged(
-            new PrivilegedAction<ResourceBundle>() {
-                public ResourceBundle run() {
-                    return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources",
-                            sun.security.util.ResourcesMgr.class.getModule());
-                }
-            }
-    );
+    private static final ResourceBundle rb =
+        ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /**
      * Initialize this {@code LoginModule}.
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java	Wed Jul 05 22:32:06 2017 +0200
@@ -306,15 +306,8 @@
 public class LdapLoginModule implements LoginModule {
 
     // Use the default classloader for this class to load the prompt strings.
-    private static final ResourceBundle rb = AccessController.doPrivileged(
-            new PrivilegedAction<ResourceBundle>() {
-                public ResourceBundle run() {
-                    return ResourceBundle.getBundle(
-                        "sun.security.util.AuthResources",
-                        sun.security.util.ResourcesMgr.class.getModule());
-                }
-            }
-        );
+    private static final ResourceBundle rb =
+        ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     // Keys to retrieve the stored username and password
     private static final String USERNAME_KEY = "javax.security.auth.login.name";
--- a/jdk/src/jdk.security.auth/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.auth/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,24 +28,22 @@
  * various authentication modules.
  */
 module jdk.security.auth {
-    requires public java.naming;
+    requires transitive java.naming;
     requires java.security.jgss;
 
     exports com.sun.security.auth;
     exports com.sun.security.auth.callback;
     exports com.sun.security.auth.login;
     exports com.sun.security.auth.module;
-    provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.Krb5LoginModule;
-    provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.UnixLoginModule;
+
+    uses sun.security.util.AuthResourcesProvider;
+
     provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.JndiLoginModule;
-    provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.KeyStoreLoginModule;
-    provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.LdapLoginModule;
-    provides javax.security.auth.spi.LoginModule with
+        com.sun.security.auth.module.Krb5LoginModule,
+        com.sun.security.auth.module.UnixLoginModule,
+        com.sun.security.auth.module.JndiLoginModule,
+        com.sun.security.auth.module.KeyStoreLoginModule,
+        com.sun.security.auth.module.LdapLoginModule,
         com.sun.security.auth.module.NTLoginModule;
 }
 
--- a/jdk/src/jdk.security.jgss/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.security.jgss/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,7 @@
  * GSSAPI mechanism.
  */
 module jdk.security.jgss {
-    requires public java.security.jgss;
+    requires transitive java.security.jgss;
     requires java.logging;
     requires java.security.sasl;
     exports com.sun.security.jgss;
--- a/jdk/src/jdk.unsupported/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/src/jdk.unsupported/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,5 +27,8 @@
     exports sun.misc;
     exports sun.reflect;
     exports com.sun.nio.file;
+
+    opens sun.misc;
+    opens sun.reflect;
 }
 
--- a/jdk/test/ProblemList.txt	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 22:32:06 2017 +0200
@@ -145,10 +145,17 @@
 
 ############################################################################
 
-# jdk_jmx
+# jdk_management
 
 com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java 8030957 aix-all
 com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java  8030957 aix-all
+
+com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java 8169575 generic-all
+
+############################################################################
+
+# jdk_jmx
+
 javax/management/MBeanServer/OldMBeanServerTest.java            8030957 aix-all
 
 javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java 8042215 generic-all
@@ -227,8 +234,6 @@
 
 javax/sound/sampled/Mixers/DisabledAssertionCrash.java 7067310 generic-all
 
-javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java 8168881 generic-all
-
 ############################################################################
 
 # jdk_imageio
@@ -306,4 +311,8 @@
 
 com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java                   8169942 linux-i586,macosx-all,windows-x64
 
+javax/rmi/PortableRemoteObject/8146975/RmiIiopReturnValueTest.java 8169737 linux-all
+
+javax/xml/ws/clientjar/TestWsImport.java			8170370 generic-all
+
 ############################################################################
--- a/jdk/test/TEST.ROOT	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/TEST.ROOT	Wed Jul 05 22:32:06 2017 +0200
@@ -26,8 +26,8 @@
 # Allow querying of various System properties in @requires clauses
 requires.properties=sun.arch.data.model java.runtime.name
 
-# Tests using jtreg 4.2 b03 features
-requiredVersion=4.2 b03
+# Tests using jtreg 4.2 b04 features
+requiredVersion=4.2 b04
 
 # Path to libraries in the topmost test directory. This is needed so @library
 # does not need ../../ notation to reach them
--- a/jdk/test/TEST.groups	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/TEST.groups	Wed Jul 05 22:32:06 2017 +0200
@@ -741,7 +741,8 @@
   java/util/ResourceBundle/Bug6359330.java  \
   java/util/Spliterator/SpliteratorCharacteristics.java  \
   java/util/Spliterator/SpliteratorCollisions.java  \
-  java/util/Spliterator/SpliteratorLateBindingFailFastTest.java  \
+  java/util/Spliterator/SpliteratorLateBindingTest.java  \
+  java/util/Spliterator/SpliteratorFailFastTest.java  \
   java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java  \
   java/util/StringJoiner/MergeTest.java  \
   java/util/StringJoiner/StringJoinerTest.java  \
--- a/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -62,9 +62,10 @@
  * @test
  * @library /test/lib
  * @build jdk.test.lib.*
- * @compile  ObjectStreamTest.java  ObjectStreamTest$_Echo_Stub.java
- *           ObjectStreamTest$_Server_Tie.java
- * @modules java.corba/com.sun.corba.se.impl.io java.base/java.io
+ * @compile ObjectStreamTest.java  ObjectStreamTest$_Echo_Stub.java
+ *          ObjectStreamTest$_Server_Tie.java
+ * @modules java.base/java.io:open
+ *          java.corba/com.sun.corba.se.impl.io:+open
  *          java.corba/com.sun.corba.se.impl.activation
  * @summary Tests of ReflectionFactory use in IIOP Serialization
  * @run testng/othervm ObjectStreamTest
--- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/Dynamic.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/Dynamic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -150,19 +150,8 @@
             int offset = ci.update(plainText, 0, plainText.length, cipherText,
                     0);
             ci.doFinal(cipherText, offset);
+            ci.init(Cipher.DECRYPT_MODE, key, ci.getParameters());
 
-            if (!mo.equalsIgnoreCase("ECB")) {
-                iv = ci.getIV();
-                aps = new IvParameterSpec(iv);
-            } else {
-                aps = null;
-            }
-
-            if (!mo.equalsIgnoreCase("GCM")) {
-                ci.init(Cipher.DECRYPT_MODE, key, aps);
-            } else {
-                ci.init(Cipher.DECRYPT_MODE, key, ci.getParameters());
-            }
             byte[] recoveredText = new byte[ci.getOutputSize(cipherText.length)];
             int len = ci.doFinal(cipherText, 0, cipherText.length,
                     recoveredText);
@@ -174,12 +163,14 @@
 
             result = Arrays.equals(plainText, tmp);
         } catch (NoSuchAlgorithmException nsaEx) {
-            nsaEx.printStackTrace();
             // CFB7 and OFB150 are negative test,SunJCE not support this
             // algorithm
             result = mo.equalsIgnoreCase("CFB7")
                     || mo.equalsIgnoreCase("OFB150");
-
+            if (!result) {
+                // only report unexpected exception
+                nsaEx.printStackTrace();
+            }
         }
         return result;
     }
--- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
 /*
  * @test
  * @bug 8069072
- * @modules java.base/com.sun.crypto.provider
+ * @modules java.base/com.sun.crypto.provider:open
  * @summary Test vectors for com.sun.crypto.provider.GHASH.
  *
  * Single iteration to verify software-only GHASH algorithm.
--- a/jdk/test/com/sun/crypto/provider/Cipher/Blowfish/TestCipherBlowfish.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/Blowfish/TestCipherBlowfish.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -42,7 +42,7 @@
                     "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
                     "OFB64"},
                 new String[]{"NoPaDDing", "PKCS5Padding"},
-                true);
+                32, 448);
     }
 
     public static void main(String[] args) throws Exception {
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,8 @@
 /**
  * @test
  * @bug 8151149
- * @modules java.base/com.sun.crypto.provider
+ * @modules java.base/javax.crypto:open
+ *          java.base/com.sun.crypto.provider:+open
  */
 
 import java.lang.reflect.*;
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 8001596
+ * @modules java.base/javax.crypto.spec:open
  * @summary Incorrect condition check in PBKDF2KeyImpl.java
  */
 
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/AESPBEWrapper.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/AESPBEWrapper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,6 +24,7 @@
 import java.io.PrintStream;
 import java.security.AlgorithmParameters;
 import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 import javax.crypto.Cipher;
 import javax.crypto.SecretKeyFactory;
@@ -69,6 +70,15 @@
      */
     @Override
     public boolean execute(int edMode, byte[] inputText, int offset, int len) {
+        boolean isUnlimited;
+        try {
+            isUnlimited =
+                (Cipher.getMaxAllowedKeyLength(this.algo) == Integer.MAX_VALUE);
+        } catch (NoSuchAlgorithmException nsae) {
+            out.println("Got unexpected exception for " + this.algo);
+            nsae.printStackTrace(out);
+            return false;
+        }
         try {
             // init Cipher
             if (Cipher.ENCRYPT_MODE == edMode) {
@@ -78,6 +88,11 @@
                 ci.init(Cipher.DECRYPT_MODE, this.key, pbeParams);
             }
 
+            if (this.algo.endsWith("AES_256") && !isUnlimited) {
+                out.print("Expected exception not thrown for " + this.algo);
+                return false;
+            }
+
             // First, generate the cipherText at an allocated buffer
             byte[] outputText = ci.doFinal(inputText, offset, len);
 
@@ -86,29 +101,19 @@
             int off = ci.update(inputText, offset, len, inputText, myoff);
             ci.doFinal(inputText, myoff + off);
 
-            if (this.algo.endsWith("AES_256")) {
-                out.print("Expected exception uncaught, "
-                        + "keyStrength > 128 within " + this.algo);
-
-                return false;
-            }
-
             // Compare to see whether the two results are the same or not
             return equalsBlock(inputText, myoff, outputText, 0,
                     outputText.length);
         } catch (Exception ex) {
             if ((ex instanceof InvalidKeyException)
-                    && this.algo.endsWith("AES_256")) {
-                out.println("Expected InvalidKeyException exception: "
-                        + ex.getMessage());
-
+                    && this.algo.endsWith("AES_256") && !isUnlimited) {
+                out.println("Expected InvalidKeyException thrown");
                 return true;
+            } else {
+                out.println("Got unexpected exception for " + algo);
+                ex.printStackTrace(out);
+                return false;
             }
-
-            out.println("Catch unexpected exception within " + algo);
-            ex.printStackTrace(out);
-
-            return false;
         }
     }
 }
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/PBECipherWrapper.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/PBESameBuffer/PBECipherWrapper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -32,6 +32,7 @@
 import java.util.StringTokenizer;
 
 import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 
 import java.io.PrintStream;
@@ -64,9 +65,25 @@
         StringTokenizer st = new StringTokenizer(algo, "/");
         String baseAlgo = st.nextToken().toUpperCase();
 
+        boolean isUnlimited;
+        try {
+            isUnlimited =
+                (Cipher.getMaxAllowedKeyLength(this.algo) == Integer.MAX_VALUE);
+        } catch (NoSuchAlgorithmException nsae) {
+            out.println("Got unexpected exception for " + this.algo);
+            nsae.printStackTrace(out);
+            return false;
+        }
+
         // Perform encryption or decryption depends on the specified edMode
         try {
             ci.init(edMode, key, aps);
+            if ((baseAlgo.endsWith("TRIPLEDES")
+                    || baseAlgo.endsWith("AES_256")) && !isUnlimited) {
+                out.print("Expected InvalidKeyException not thrown: "
+                    + this.algo);
+                return false;
+            }
 
             // First, generate the cipherText at an allocated buffer
             byte[] outputText = ci.doFinal(inputText, offset, len);
@@ -78,33 +95,24 @@
 
             ci.doFinal(inputText, myoff + off);
 
-            if (baseAlgo.endsWith("TRIPLEDES")
-                    || baseAlgo.endsWith("AES_256")) {
-                out.print("Expected exception uncaught,"
-                        + "keyStrength > 128 within " + this.algo);
-
-                return false;
-            }
-
             // Compare to see whether the two results are the same or not
             boolean result = equalsBlock(inputText, myoff, outputText, 0,
                     outputText.length);
 
             return result;
         } catch (Exception ex) {
-            if ((ex instanceof InvalidKeyException)
-                    && (baseAlgo.endsWith("TRIPLEDES")
-                    || baseAlgo.endsWith("AES_256"))) {
-                out.println("Expected InvalidKeyException exception: "
-                        + ex.getMessage());
-
+            if ((ex instanceof InvalidKeyException) &&
+                    (baseAlgo.endsWith("TRIPLEDES")
+                        || baseAlgo.endsWith("AES_256")) &&
+                !isUnlimited) {
+                out.println("Expected InvalidKeyException thrown for "
+                    + algo);
                 return true;
+            } else {
+                out.println("Got unexpected exception for " + algo);
+                ex.printStackTrace(out);
+                return false;
             }
-
-            out.println("Catch unexpected exception within " + algo);
-            ex.printStackTrace(out);
-
-            return false;
         }
     }
 }
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherKeyWrapperPBEKey.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherKeyWrapperPBEKey.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -120,6 +120,9 @@
                 = new StringTokenizer(algo, "/").nextToken().toUpperCase();
         boolean isAES = baseAlgo.contains("AES");
 
+        boolean isUnlimited =
+            (Cipher.getMaxAllowedKeyLength(algo) == Integer.MAX_VALUE);
+
         try {
             // Initialization
             new Random().nextBytes(salt);
@@ -129,7 +132,6 @@
             SecretKey key = skf.generateSecret(new PBEKeySpec(
                     "Secret Key".toCharArray()));
             Cipher ci = Cipher.getInstance(algo);
-
             if (isAES) {
                 ci.init(Cipher.WRAP_MODE, key);
                 pbeParams = ci.getParameters();
@@ -146,10 +148,10 @@
 
             Key unwrappedKey = ci.unwrap(keyWrapper, algo, Cipher.SECRET_KEY);
 
-            if (baseAlgo.endsWith("TRIPLEDES")
-                    || baseAlgo.endsWith("AES_256")) {
+            if ((baseAlgo.endsWith("TRIPLEDES")
+                    || baseAlgo.endsWith("AES_256")) && !isUnlimited) {
                 out.print(
-                        "InvalidKeyException not thrown when keyStrength > 128");
+                        "Expected InvalidKeyException not thrown");
                 return false;
             }
 
@@ -158,8 +160,9 @@
         } catch (InvalidKeyException ex) {
 
             if ((baseAlgo.endsWith("TRIPLEDES")
-                    || baseAlgo.endsWith("AES_256"))) {
-                out.println("Expected InvalidKeyException, keyStrength > 128");
+                    || baseAlgo.endsWith("AES_256")) && !isUnlimited) {
+                out.print(
+                        "Expected InvalidKeyException thrown");
                 return true;
             } else {
                 throw ex;
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBE.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBE.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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,6 +79,9 @@
 
         out.println("=> Testing: " + algorithm);
 
+        boolean isUnlimited =
+            (Cipher.getMaxAllowedKeyLength(algorithm) == Integer.MAX_VALUE);
+
         try {
             // Initialization
             AlgorithmParameterSpec algoParamSpec
@@ -98,9 +101,9 @@
             ci.init(Cipher.DECRYPT_MODE, secretKey, algoParamSpec);
             byte[] recoveredText = ci.doFinal(cipherText);
 
-            if (algorithm.contains("TripleDES")) {
+            if (algorithm.contains("TripleDES") && !isUnlimited) {
                 throw new RuntimeException(
-                        "Expected InvalidKeyException exception uncaugh");
+                        "Expected InvalidKeyException not thrown");
             }
 
             // Comparison
@@ -110,8 +113,8 @@
             }
             out.println("Test Passed.");
         } catch (InvalidKeyException ex) {
-            if (algorithm.contains("TripleDES")) {
-                out.println("Expected InvalidKeyException raised");
+            if (algorithm.contains("TripleDES") && !isUnlimited) {
+                out.println("Expected InvalidKeyException thrown");
             } else {
                 throw new RuntimeException(ex);
             }
--- a/jdk/test/com/sun/crypto/provider/Cipher/TestCipher.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/crypto/provider/Cipher/TestCipher.java	Wed Jul 05 22:32:06 2017 +0200
@@ -49,14 +49,13 @@
     private final String[] MODES;
     private final String[] PADDINGS;
 
-    /* Used to test cipher with different key strengths
-       Key size tested is increment of KEYCUTTER from MINIMUM_KEY_SIZE to
-       maximum allowed keysize.
-       DES/DESede/Blowfish work with currently selected key sizes.
+    /* Used to test variable-key-length ciphers:
+       Key size tested is increment of KEYCUTTER from minKeySize
+       to min(maxKeySize, Cipher.getMaxAllowedKeyLength(algo)).
     */
-    private final int variousKeySize;
     private final int KEYCUTTER = 8;
-    private final int MINIMUM_KEY_SIZE = 32;
+    private final int minKeySize;
+    private final int maxKeySize;
 
     // Used to assert that Encryption/Decryption works with same buffer
     // TEXT_LEN is multiple of blocks in order to work against ciphers w/ NoPadding
@@ -68,23 +67,28 @@
     private final byte[] IV;
     private final byte[] INPUT_TEXT;
 
+    // for variable-key-length ciphers
     TestCipher(String algo, String[] modes, String[] paddings,
-            boolean keyStrength) throws NoSuchAlgorithmException {
+            int minKeySize, int maxKeySize) throws NoSuchAlgorithmException {
         ALGORITHM = algo;
         MODES = modes;
         PADDINGS = paddings;
-        this.variousKeySize
-                = keyStrength ? Cipher.getMaxAllowedKeyLength(ALGORITHM) : 0;
-
+        this.minKeySize = minKeySize;
+        int maxAllowedKeySize = Cipher.getMaxAllowedKeyLength(ALGORITHM);
+        if (maxKeySize > maxAllowedKeySize) {
+            maxKeySize = maxAllowedKeySize;
+        }
+        this.maxKeySize = maxKeySize;
         IV = generateBytes(8);
         INPUT_TEXT = generateBytes(TEXT_LEN + PAD_BYTES + ENC_OFFSET);
     }
 
+    // for fixed-key-length ciphers
     TestCipher(String algo, String[] modes, String[] paddings) {
         ALGORITHM = algo;
         MODES = modes;
         PADDINGS = paddings;
-        variousKeySize = 0;
+        this.minKeySize = this.maxKeySize = 0;
 
         IV = generateBytes(8);
         INPUT_TEXT = generateBytes(TEXT_LEN + PAD_BYTES + ENC_OFFSET);
@@ -98,8 +102,8 @@
         return bytes;
     }
 
-    private boolean isKeyStrenthSupported() {
-        return (variousKeySize != 0);
+    private boolean isMultipleKeyLengthSupported() {
+        return (maxKeySize != minKeySize);
     }
 
     public void runAll() throws InvalidKeyException,
@@ -110,11 +114,11 @@
 
         for (String mode : MODES) {
             for (String padding : PADDINGS) {
-                if (!isKeyStrenthSupported()) {
-                    runTest(mode, padding, 0);
+                if (!isMultipleKeyLengthSupported()) {
+                    runTest(mode, padding, minKeySize);
                 } else {
-                    int keySize = variousKeySize;
-                    while (keySize >= MINIMUM_KEY_SIZE) {
+                    int keySize = maxKeySize;
+                    while (keySize >= minKeySize) {
                         out.println("With Key Strength: " + keySize);
                         runTest(mode, padding, keySize);
                         keySize -= KEYCUTTER;
@@ -139,6 +143,7 @@
         if (keySize != 0) {
             kg.init(keySize);
         }
+
         SecretKey key = kg.generateKey();
         SecretKeySpec skeySpec = new SecretKeySpec(key.getEncoded(), ALGORITHM);
 
@@ -150,7 +155,6 @@
         }
 
         // Encryption
-
         byte[] plainText = INPUT_TEXT.clone();
 
         // Generate cipher and save to separate buffer
--- a/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,7 @@
  *
  *  @author Egor Ushakov
  *
- *  @modules jdk.jdi/com.sun.tools.jdi
+ *  @modules jdk.jdi/com.sun.tools.jdi:+open
  *  @run build TestScaffold VMConnection
  *  @run compile -g ConstantPoolInfoGC.java
  *  @run main/othervm ConstantPoolInfoGC
--- a/jdk/test/com/sun/jdi/ModulesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/jdi/ModulesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -78,7 +78,6 @@
         }
         // Sanity checks: make sure there is no crash or exception
         String otherName = other.name();
-        boolean cond = module.canRead(other);
         return true;
     }
 
@@ -159,8 +158,6 @@
             }
             bootUnnamedModule = module;
         }
-        boolean cond = module.canRead(other);
-        println("    can read: " + cond);
     }
 
     // Check that the java.lang.String class was loaded by the java.base module.
@@ -198,24 +195,6 @@
             testFailed = true;
             println(FailPrefix + "unnamed module of PlatformClassLoader was not observed");
         }
-
-        for (ModuleReference module : modules) {
-            if (!bootUnnamedModule.canRead(module)) {
-                testFailed = true;
-                println(FailPrefix + "boot unnamed module must read any module" +
-                        "but a non-readible module is found: " + module.name());
-            }
-            if (!appUnnamedModule.canRead(module)) {
-                testFailed = true;
-                println(FailPrefix + "app unnamed module must read any module" +
-                        "but a non-readible module is found: " + module.name());
-            }
-            if (!extUnnamedModule.canRead(module)) {
-                testFailed = true;
-                println(FailPrefix + "ext unnamed module must read any module" +
-                        "but a non-readible module is found: " + module.name());
-            }
-        }
     }
 
     protected void runTests() throws Exception {
--- a/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,8 +30,8 @@
  * to encapsulate the transport. This tests that the connectors are
  * created and that they have an "address" argument.
  *
- * @modules jdk.jdi
- * @build GeneratedConnectors NullTransportService
+ * @modules jdk.jdi/com.sun.tools.jdi
+ * @build GeneratedConnectors NullTransportService SimpleLaunchingConnector
  * @run main/othervm GeneratedConnectors
  */
 
--- a/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -33,7 +33,7 @@
  *          with a lower-case letter
  *
  * @author Jaroslav Bachorik
- * @modules java.management/com.sun.jmx.mbeanserver
+ * @modules java.management/com.sun.jmx.mbeanserver:open
  * @run clean SimpleIntrospectorTest
  * @run build SimpleIntrospectorTest BeanClass
  * @run main SimpleIntrospectorTest
--- a/jdk/test/com/sun/jndi/dns/Parser.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/jndi/dns/Parser.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8035105
  * @summary DNS resource record parsing
- * @modules jdk.naming.dns/com.sun.jndi.dns
+ * @modules jdk.naming.dns/com.sun.jndi.dns:+open
  * @compile --add-modules jdk.naming.dns Parser.java
  */
 
--- a/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8158802
  * @summary com.sun.jndi.ldap.SimpleClientId produces wrong hash code
- * @modules java.naming/com.sun.jndi.ldap
+ * @modules java.naming/com.sun.jndi.ldap:open
  */
 
 import java.io.OutputStream;
--- a/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -28,8 +28,9 @@
  * @modules jdk.naming.rmi/com.sun.jndi.rmi.registry java.rmi/sun.rmi.registry
  *     java.rmi/sun.rmi.server java.rmi/sun.rmi.transport java.rmi/sun.rmi.transport.tcp
  * @library ../../../../../../java/rmi/testlibrary
+ * @build TestLibrary
  * @compile --add-modules jdk.naming.rmi ContextWithNullProperties.java
- * @run main ContextWithNullProperties
+ * @run main/othervm ContextWithNullProperties
  */
 
 import com.sun.jndi.rmi.registry.RegistryContext;
@@ -37,7 +38,7 @@
 
 public class ContextWithNullProperties {
     public static void main(String[] args) throws Exception {
-        Registry registry = TestLibrary.createRegistryOnUnusedPort();
+        Registry registry = TestLibrary.createRegistryOnEphemeralPort();
         int registryPort = TestLibrary.getRegistryPort(registry);
         System.out.println("Connecting to the default Registry...");
         // Connect to the default Registry.
--- a/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/UnbindIdempotent.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/UnbindIdempotent.java	Wed Jul 05 22:32:06 2017 +0200
@@ -31,7 +31,7 @@
  *     jdk.naming.rmi
  * @library ../../../../../../java/rmi/testlibrary
  * @build TestLibrary
- * @run main UnbindIdempotent
+ * @run main/othervm UnbindIdempotent
  */
 
 import java.rmi.registry.Registry;
@@ -43,7 +43,7 @@
 public class UnbindIdempotent {
 
     public static void main(String[] args) throws Exception {
-        Registry registry = TestLibrary.createRegistryOnUnusedPort();
+        Registry registry = TestLibrary.createRegistryOnEphemeralPort();
         int registryPort = TestLibrary.getRegistryPort(registry);
         InitialContext ictx = new InitialContext();
         Context rctx;
--- a/jdk/test/com/sun/management/VMOptionOpenDataTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/management/VMOptionOpenDataTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -21,58 +21,77 @@
  * questions.
  */
 
+import com.sun.management.HotSpotDiagnosticMXBean;
 import com.sun.management.VMOption;
-import java.io.InvalidObjectException;
-import java.util.Objects;
-import javax.management.openmbean.OpenDataException;
-import sun.management.MappedMXBeanType;
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.management.MBeanServerConnection;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+
+import static javax.management.openmbean.SimpleType.*;
 
 /*
  * @test
  * @bug     8042901
  * @summary Check that MappedMXBeanType.toOpenTypeData supports VMOption
- * @modules java.management/sun.management
- *          jdk.management/com.sun.management
+ * @modules jdk.management/com.sun.management
  * @author  Shanliang Jiang
  */
 public class VMOptionOpenDataTest {
-    public static void main(String[] args) throws Exception {
-        System.out.println("--- VMOptionOpenDataTest-main: Checking that "
-                + "MappedMXBeanType.toOpenTypeData supports VMOption");
-        Exception failed = null;
-        try {
-            VMOption vo = new VMOption("toto", "titi", true, VMOption.Origin.OTHER);
-            System.out.println("--- Construct a VMOption object: \"" + vo + "\"");
+    private static final String[] names = new String[] {
+        "name", "value", "origin", "writeable"
+    };
+    private static final OpenType[] types = new OpenType[] {
+        STRING, STRING, STRING, BOOLEAN
+    };
 
-            Object open = MappedMXBeanType.toOpenTypeData(vo, VMOption.class);
-            System.out.println("--- Map it to an open type:  \"" + open +" \"");
+    public static void main(String... args) throws Exception {
+        MBeanServerConnection msc = ManagementFactory.getPlatformMBeanServer();
+        HotSpotDiagnosticMXBean mxbean =
+            ManagementFactory.getPlatformMXBean(msc, HotSpotDiagnosticMXBean.class);
+
 
-            Object back = MappedMXBeanType.toJavaTypeData(open, VMOption.class);
-            System.out.println("--- Map it back to java type:  \"" + back +" \"");
+        String[] signatures = new String[] {
+            String.class.getName()
+        };
+        Object obj = msc.invoke(mxbean.getObjectName(), "getVMOption",
+            new String[] { "PrintVMOptions"}, signatures);
 
-            if (back == null) {
-                failed = new RuntimeException("Failed, mapping back got null.");
-            } else if (!(back instanceof VMOption)) {
-                failed = new RuntimeException("Failed, not mapped back to a VMOption: "
-                        +back.getClass());
-            } else {
-                VMOption mapBack = (VMOption)back;
-                if (!Objects.equals(vo.getName(), mapBack.getName()) ||
-                        !Objects.equals(vo.getOrigin(), mapBack.getOrigin()) ||
-                        !Objects.equals(vo.getValue(), mapBack.getValue()) ||
-                        vo.isWriteable() != mapBack.isWriteable()) {
-                    failed = new RuntimeException(
-                            "Failed, failed to map back the original VMOtion.");
-                }
+        CompositeData data = (CompositeData)obj;
+        validateType(data);
+
+        VMOption option = mxbean.getVMOption("PrintVMOptions");
+        VMOption o = VMOption.from(data);
+        assertEquals(option, o);
+    }
+
+    private static void validateType(CompositeData data) {
+        CompositeType type = data.getCompositeType();
+        Set<String> keys = Arrays.stream(names).collect(Collectors.toSet());
+        if (!type.keySet().equals(keys)) {
+            throw new RuntimeException("key not matched: " + type.keySet().toString());
+        }
+        for (int i=0; i < names.length; i++) {
+            OpenType t = type.getType(names[i]);
+            if (t != types[i]) {
+                throw new AssertionError(names[i] + ": type not matched: " +
+                    t + " expected: " + types[i]);
             }
-        } catch (OpenDataException | InvalidObjectException ode) {
-            failed = ode;
-        }
-        if (failed == null) {
-            System.out.println("--- PASSED!");
-        } else {
-            System.out.println("--- Failed: "+failed.getMessage());
-            throw failed;
         }
     }
+
+    private static void assertEquals(VMOption o1, VMOption o2) {
+        if (!o1.getName().equals(o2.getName()) ||
+            !o1.getOrigin().equals(o2.getOrigin()) ||
+            !o1.getValue().equals(o2.getValue()) ||
+            o1.isWriteable() != o2.isWriteable()) {
+            throw new AssertionError(o1 + " != " + o2);
+        }
+
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/security/auth/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,1 @@
+modules = jdk.security.auth
--- a/jdk/test/com/sun/security/jgss/InquireSecContextPermissionCheck.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/security/jgss/InquireSecContextPermissionCheck.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -21,9 +21,10 @@
  * questions.
  */
 
-/**
+/*
  * @test
  * @bug 6710360
+ * @modules jdk.security.jgss
  * @summary export Kerberos session key to applications
  */
 
--- a/jdk/test/com/sun/security/sasl/Cram.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/com/sun/security/sasl/Cram.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 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
@@ -24,15 +24,17 @@
 /*
  * @test
  * @bug 4634892
+ * @modules jdk.security.auth
  * @summary Ensure that authentication via CRAM-MD5 works.
  */
 
 /*
  * Can set logging to FINEST to view exchange.
  */
-import javax.security.sasl.*;
-import javax.security.auth.callback.*;
-import java.security.Security;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslServer;
 
 public class Cram {
     private static final String MECH = "CRAM-MD5";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/security/sasl/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,1 @@
+modules = java.security.sasl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/security/sasl/digest/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,1 @@
+modules = jdk.security.auth
--- a/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,6 +27,7 @@
   @summary [macosx] TwentyThousandTest test intermittently hangs
   @author Oleg Pekhovskiy
   @modules java.desktop/sun.awt
+  @modules java.desktop/java.awt:open
   @run main EDTShutdownTest
  */
 
--- a/jdk/test/java/awt/Focus/DisposedWindow/DisposeDialogNotActivateOwnerTest/DisposeDialogNotActivateOwnerTest.html	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-<!--
- Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
- This code is free software; you can redistribute it and/or modify it
- 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.
--->
-
-<html>
-<!--
-  @test
-  @key headful
-  @bug        6386592
-  @summary    Tests that disposing a dialog doesn't activate its invisible owner.
-  @author     anton.tarasov@sun.com: area=awt.focus
-  @run        applet DisposeDialogNotActivateOwnerTest.html
-  -->
-<head>
-<title>DisposeDialogNotActivateOwnerTest</title>
-</head>
-<body>
- 
-<h1>DisposeDialogNotActivateOwnerTest<br>Bug ID: 6386592</h1>
- 
-<p>See the dialog box (usually in upper left corner) for instructions</p>
- 
-<APPLET CODE=DisposeDialogNotActivateOwnerTest.class WIDTH=200 HEIGHT=200></APPLET>
-</body>
-</html>
--- a/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
   @library ../../regtesthelpers
   @modules java.desktop/java.awt.peer
            java.desktop/sun.awt
+           java.desktop/java.awt:open
   @build Util
   @run main RequestOnCompWithNullParent1
 */
--- a/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html	Wed Jul 05 22:32:06 2017 +0200
@@ -30,7 +30,7 @@
   @requires (os.family == "linux" | os.family == "solaris")
   @modules java.desktop/sun.awt
            java.desktop/java.awt.peer
-           java.desktop/sun.awt.X11
+           java.desktop/sun.awt.X11:open
   @run applet FocusEmptyListTest.html
   -->
 <head>
--- a/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,7 @@
   @summary The test checks that Container's method startLWModal
 and stopLWModal work correctly. The test scenario is very close
 to JOptionPane.showInternal*Dialog methods
+  @modules java.desktop/java.awt:open
   @author artem.ananiev@...: area=awt.modal
   @library ../../regtesthelpers
   @build Util
--- a/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,7 +34,7 @@
  * @requires (os.family == "linux" | os.family == "solaris")
  * @modules java.desktop/sun.awt
  *          java.desktop/java.awt.peer
- *          java.desktop/sun.awt.X11
+ *          java.desktop/sun.awt.X11:open
  * @author Sean Chou
  */
 
--- a/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -154,16 +154,16 @@
 case "$OS" in
   Windows* | CYGWIN* )
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
                          TestWrapped sun.awt.windows.WToolkit
     status=$?
     if [ ! $status -eq "0" ]; then
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.awt.windows.WToolkit";
     fi
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.awt.windows.WToolkit \
                          TestWrapped sun.awt.windows.WToolkit
     status=$?
@@ -174,8 +174,8 @@
 
   SunOS | Linux )
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.awt.X11.XToolkit \
                          TestWrapped sun.awt.X11.XToolkit
     status=$?
@@ -183,8 +183,8 @@
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.awt.xawt.XToolkit";
     fi
     AWT_TOOLKIT=XToolkit ${TESTJAVA}/bin/java ${TESTVMOPTS} \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
                                               -Djava.awt.headless=true \
                                               TestWrapped sun.awt.X11.XToolkit
     status=$?
@@ -195,16 +195,16 @@
 
   Darwin)
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
                          TestWrapped sun.lwawt.macosx.LWCToolkit
     status=$?
     if [ ! $status -eq "0" ]; then
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.lwawt.macosx.LWCToolkit";
     fi
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.lwawt.macosx.LWCToolkit \
                          TestWrapped sun.lwawt.macosx.LWCToolkit
     status=$?
--- a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,6 +30,7 @@
  *          of the ActionEvent triggered when TrayIcon is double clicked
  *          (single clicked, on Mac)
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library ../../../../lib/testlibrary ../
  * @library /java/awt/patchlib
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java	Wed Jul 05 22:32:06 2017 +0200
@@ -33,6 +33,7 @@
  *          triggered when multiple AWTEventListeners and ActionListeners
  *          are added.
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,8 @@
  * @test
  * @bug 6191390 8154328
  * @summary Verify that ActionEvent is received with correct modifiers set.
+ * @modules java.desktop/java.awt:open
+ * @modules java.desktop/java.awt.peer
  * @library ../../../../lib/testlibrary ../
  * @library /java/awt/patchlib
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build ExtendedRobot SystemTrayIconHelper
--- a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,6 +32,7 @@
  *          checks if all listeners are triggered when AWTEventListeners
  *          and MouseListeners are added.
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../../lib/testlibrary ../../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -39,6 +39,7 @@
  * @key headful
  * @summary Check if MouseEvent has the proper modifiers when
  *          TrayIcon is clicked pressing the modifier keys
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,6 +30,7 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,6 +34,7 @@
  *          it is double clicked with mouse button 1 on windows
  *          or single clicked with button 3 on Mac OS X
  *          or single clicked with button 1 on rest.
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
  * @summary Check if a JPopupMenu can be displayed when TrayIcon is
  *          right clicked. It uses a JWindow as the parent of the JPopupMenu
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
   @key headful
   @bug 6758673
   @summary Tests that windows are removed from owner's child windows list
+  @modules java.desktop/java.awt:open
   @author art: area=awt.toplevel
   @run main/othervm -mx128m OwnedWindowsLeak
 */
--- a/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,6 +27,7 @@
   @bug 6315717
   @summary verifies that InputEvents button masks arrays are the same
   @author Andrei Dmitriev : area=awt.event
+  @modules java.desktop/java.awt.event:open
   @run main ButtonArraysEquality
  */
 
--- a/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
   @test %I% %E%
   @key headful
   @bug 6315717
+  @modules java.desktop/java.awt.event:open
   @summary verifies that InputEvent.getMaskForButton() returns the same values as in InputEvent.BUTTON_DOWN_MASK
   @author Andrei Dmitriev : area=awt.event
   @run main CheckGetMaskForButton
--- a/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 4351212
- * @modules java.desktop/sun.font
+ * @modules java.desktop/sun.font:open
  * @summary Verify that new getLCIDFromLocale method works
  */
 
--- a/jdk/test/java/awt/image/MultiResolutionImageTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/image/MultiResolutionImageTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -48,7 +48,7 @@
  * @requires (os.family == "mac")
  * @modules java.desktop/sun.awt
  *          java.desktop/sun.awt.image
- *          java.desktop/sun.lwawt.macosx
+ *          java.desktop/sun.lwawt.macosx:open
  * @run main MultiResolutionImageTest TOOLKIT_PREPARE
  * @run main MultiResolutionImageTest TOOLKIT_LOAD
  * @run main MultiResolutionImageTest TOOLKIT
--- a/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,6 @@
 public class Helper {
     private Helper() { }
     public static void addExports(String pn, Module target) {
-        java.awt.Component.class.getModule().addExports(pn, target);
+        java.awt.Component.class.getModule().addOpens(pn, target);
     }
 }
--- a/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 6380849
  * @summary Tests BeanInfo finder
+ * @modules java.desktop/java.beans:open
  * @author Sergey Malenkov
  */
 
--- a/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 8007458
  * @summary Tests CardLayout encoding
+ * @modules java.desktop/java.awt:open
  * @author Sergey Malenkov
  */
 
--- a/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 8007458
  * @summary Tests GridBagLayout encoding
+ * @modules java.desktop/java.awt:open
  * @author Sergey Malenkov
  */
 
--- a/jdk/test/java/io/FilePermission/Correctness.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/io/FilePermission/Correctness.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  *
  * @test
  * @bug 8164705
+ * @modules java.base/java.io:open
  * @summary Remove pathname canonicalization from FilePermission
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/FilePermission/MergeName.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,84 @@
+/*
+ * 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.ProcessTools;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * @test
+ * @bug 8170364
+ * @summary FilePermission path modified during merge
+ * @library /test/lib
+ */
+
+public class MergeName {
+
+    public static final String[] ALL_ACTIONS
+            = {"read", "write", "execute", "delete"};
+
+    public static void main(String[] args) throws Exception {
+        if (args.length == 0) {
+            test("p1", "read", "write", "delete", "execute");
+            test("p2", "read,write", "delete,execute");
+            test("p3", "read,write,delete", "execute");
+            test("p4", "read,write,delete,execute");
+        } else {
+            SecurityManager sm = System.getSecurityManager();
+            for (String arg : args) {
+                // Use bits to create powerset of ALL_ACTIONS
+                IntStream.range(1, 16)
+                        .mapToObj(n -> IntStream.range(0, 4)
+                                .filter(x -> (n & (1 << x)) != 0)
+                                .mapToObj(x -> ALL_ACTIONS[x])
+                                .collect(Collectors.joining(",")))
+                        .forEach(a -> sm.checkPermission(
+                                new FilePermission(arg, a)));
+            }
+        }
+    }
+
+    private static void test(String file, String... actions) throws Exception {
+        List<String> content = new ArrayList<>();
+        content.add("grant {");
+        for (String action : actions) {
+            content.add("   permission java.io.FilePermission " +
+                    "\"x\", \"" +action + "\";");
+        }
+        content.add("};");
+        Files.write(Paths.get(file), content);
+        ProcessTools.executeTestJvm("-Djava.security.manager",
+                "-Djava.security.policy=" + file,
+                "MergeName",
+                "x",
+                new File(System.getProperty("user.dir"), "x").getPath())
+            .shouldHaveExitValue(0);
+    }
+}
--- a/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,6 +30,7 @@
 /*
  * @test
  * @bug 8067870
+ * @modules java.base/java.io:open
  * @summary verifies java.io.ObjectInputStream.PeekInputStream.skip works
  *          as intended
  */
--- a/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,8 @@
  * @bug 8080535
  * @summary Expected size of Character.UnicodeBlock.map is not optimal
  * @library /lib/testlibrary
+ * @modules java.base/java.lang:open
+ *          java.base/java.util:open
  * @build jdk.testlibrary.OptimalCapacity
  * @run main OptimalMapSize
  */
--- a/jdk/test/java/lang/Class/GetModuleTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/GetModuleTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -31,7 +31,6 @@
  */
 
 import java.awt.Component;
-import java.lang.reflect.Field;
 import java.lang.reflect.Module;
 
 import jdk.internal.org.objectweb.asm.ClassWriter;
@@ -44,16 +43,7 @@
 
 public class GetModuleTest {
 
-    static final Unsafe U;
-    static {
-        try {
-            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-            theUnsafe.setAccessible(true);
-            U = (Unsafe) theUnsafe.get(null);
-        } catch (Exception e) {
-            throw new AssertionError(e);
-        }
-    }
+    private static final Unsafe U = Unsafe.getUnsafe();
 
     private static final Module TEST_MODULE = GetModuleTest.class.getModule();
 
--- a/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -44,7 +44,7 @@
         try {
             Class<?> c = findClass(m1, "p1.internal.B");
             c.newInstance();
-            throw new RuntimeException(c.getName() + " is not exported to m2");
+            throw new RuntimeException(c.getName() + " should not be exported to m2");
         } catch (IllegalAccessException e) {}
     }
 
--- a/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -40,6 +40,7 @@
  *          set accessible if the right permission is granted; this test
  *          also verifies that Class.classLoader final private field is
  *          hidden from reflection access.
+ * @modules java.base/java.lang:open
  * @run main/othervm ClassDeclaredFieldsTest UNSECURE
  * @run main/othervm ClassDeclaredFieldsTest SECURE
  *
--- a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -58,9 +58,9 @@
 /**
  * @test
  * @bug 8065552
- * @summary test that all fields returned by getDeclaredFields() can be
- *          set accessible if the right permission is granted; this test
- *          loads all the classes in the BCL, get their declared fields,
+ * @summary test that all public fields returned by getDeclaredFields() can
+ *          be set accessible if the right permission is granted; this test
+ *          loads all classes and get their declared fields
  *          and call setAccessible(false) followed by setAccessible(true);
  * @modules java.base/jdk.internal.module
  * @run main/othervm --add-modules=ALL-SYSTEM FieldSetAccessibleTest UNSECURE
@@ -81,24 +81,30 @@
 
 
     // Test that all fields for any given class can be made accessibles
-    static void testSetFieldsAccessible(Class<?> c, boolean expectException) {
+    static void testSetFieldsAccessible(Class<?> c) {
+        Module self = FieldSetAccessibleTest.class.getModule();
+        Module target = c.getModule();
+        String pn = c.getPackageName();
+        boolean exported = self.canRead(target) && target.isExported(pn, self);
         for (Field f : c.getDeclaredFields()) {
             fieldCount.incrementAndGet();
-            boolean expect = expectException;
-            if ((c == Module.class || c == AccessibleObject.class) &&
-                !Modifier.isPublic(f.getModifiers())) {
-                expect = true;
-            }
+
+            // setAccessible succeeds only if it's exported and the member
+            // is public and of a public class, or it's opened
+            // otherwise it would fail.
+            boolean isPublic = Modifier.isPublic(f.getModifiers()) &&
+                Modifier.isPublic(c.getModifiers());
+            boolean access = (exported && isPublic) || target.isOpen(pn, self);
             try {
                 f.setAccessible(false);
                 f.setAccessible(true);
-                if (expect) {
+                if (!access) {
                     throw new RuntimeException(
                         String.format("Expected InaccessibleObjectException is not thrown "
                                       + "for field %s in class %s%n", f.getName(), c.getName()));
                 }
             } catch (InaccessibleObjectException expected) {
-                if (!expect) {
+                if (access) {
                     throw new RuntimeException(expected);
                 }
             }
@@ -110,18 +116,17 @@
     public static boolean test(Class<?> c, boolean addExports) {
         Module self = FieldSetAccessibleTest.class.getModule();
         Module target = c.getModule();
-        String pn = c.getPackage().getName();
+        String pn = c.getPackageName();
         boolean exported = self.canRead(target) && target.isExported(pn, self);
         if (addExports && !exported) {
             Modules.addExports(target, pn, self);
             exported = true;
         }
-        boolean expectException = !exported;
 
         classCount.incrementAndGet();
 
         // Call getDeclaredFields() and try to set their accessible flag.
-        testSetFieldsAccessible(c, expectException);
+        testSetFieldsAccessible(c);
 
         // add more tests here...
 
--- a/jdk/test/java/lang/Class/getResource/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/getResource/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,6 @@
 import java.lang.module.Configuration;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -33,8 +32,8 @@
 import java.nio.file.Paths;
 
 /**
- * Basic test of Class getResource and getResourceAsStream when invoked from
- * code in named modules.
+ * Basic test of Class getResource and getResourceAsStream to locate/read
+ * resources in named modules.
  */
 
 public class Main {
@@ -43,62 +42,192 @@
 
     public static void main(String[] args) throws IOException {
 
-        // create m1/myresource containing "m1"
-        Path file = directoryFor("m1").resolve(NAME);
-        Files.write(file, "m1".getBytes("UTF-8"));
+        // create resources in m1
+        createResource("m1", Paths.get("."), "m1");
+        createResource("m1", Paths.get("p1"), "m1/p1");
+        createResource("m1", Paths.get("p1", "impl"), "m1/p1.impl");
+        createResource("m1", Paths.get("p1", "resources"), "m1/p1.resources");
+
+        // create resources in m2
+        createResource("m2", Paths.get("."), "m2");
+        createResource("m2", Paths.get("p2"), "m2/p2");
+        createResource("m2", Paths.get("p2", "impl"), "m2/p2.impl");
+        createResource("m2", Paths.get("p2", "resources"), "m2/p2.resources");
+
+
+        // invoke Class getResource from an unnamed module.
+        URL url = Main.class.getResource("/" + NAME);
+        assertNotNull(url);
+
+        url = Main.class.getResource("/p1/" + NAME);
+        assertNull(url);
 
-        // create m2/myresource containing "m2"
-        file = directoryFor("m2").resolve(NAME);
-        Files.write(file, "m2".getBytes("UTF-8"));
+        url = Main.class.getResource("/p1/impl/" + NAME);
+        assertNull(url);
+
+        url = Main.class.getResource("/p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        url = Main.class.getResource("/p2/" + NAME);
+        assertNull(url);
+
+        url = Main.class.getResource("/p2/impl/" + NAME);
+        assertNull(url);
 
-        // check that m3/myresource does not exist
-        assertTrue(Files.notExists(directoryFor("m3").resolve(NAME)));
+        // m1: exports private p1.resources
+        url = Main.class.getResource("/p2/resources/" + NAME);
+        assertNull(url);
+
+
+        // invoke Class getResource from module m1
+        url = p1.Main.getResource("/" + NAME);
+        assertEquals(readAllAsString(url), "m1");
+
+        url = p1.Main.getResource("/p1/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1");
 
-        // invoke Class getResource from the unnamed module
-        URL url0 = Main.class.getResource("/" + NAME);
-        assertNull(url0);
+        url = p1.Main.getResource("/p1/impl/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.impl");
+
+        url = p1.Main.getResource("/p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        // m2: not a named package
+        url = p1.Main.getResource(p2.Main.class, "/" + NAME);
+        assertEquals(readAllAsString(url), "m2");
+
+        url = p1.Main.getResource(p2.Main.class, "/p2/" + NAME);
+        assertNull(url);
+
+        // m2: exports p2.impl to m1
+        url = p1.Main.getResource(p2.Main.class, "/p2/impl/" + NAME);
+        assertNull(url);
+
+        // m2: exports private p2.resources to m1;
+        url = p1.Main.getResource(p2.Main.class, "/p2/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m2/p2.resources");
+
 
-        // invoke Class getResource from modules m1-m3
-        URL url1 = p1.Main.getResource("/" + NAME);
-        URL url2 = p2.Main.getResource("/" + NAME);
-        URL url3 = p3.Main.getResource("/" + NAME);
-        assertNotNull(url1);
-        assertNotNull(url2);
-        assertNull(url3);
+        // invoke Class getResource from module m2
+        url = p2.Main.getResource("/" + NAME);
+        assertEquals(readAllAsString(url), "m2");
+
+        url = p2.Main.getResource("/p2/" + NAME);
+        assertEquals(readAllAsString(url), "m2/p2");
+
+        url = p2.Main.getResource("/p2/impl/" + NAME);
+        assertEquals(readAllAsString(url), "m2/p2.impl");
+
+        url = p2.Main.getResource("/p2/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m2/p2.resources");
 
-        // check contents of resurces at url1 and url2
-        assertEquals(new String(readAll(url1), "UTF-8"), "m1");
-        assertEquals(new String(readAll(url2), "UTF-8"), "m2");
+        // m1: not a named package
+        url = p2.Main.getResource(p1.Main.class, "/" + NAME);
+        assertEquals(readAllAsString(url), "m1");
+
+        url = p2.Main.getResource(p1.Main.class, "/p1/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResource(p1.Main.class, "/p1/impl/" + NAME);
+        assertNull(url);
+
+        // m1: exports private p1.resources;
+        url = p2.Main.getResource(p1.Main.class, "/p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
 
-        // invoke Class getResourceAsStream from the unnamed module
-        InputStream in0 = Main.class.getResourceAsStream("/" + NAME);
-        assertNull(in0);
+
+        // invoke Class getResourceAsStream from an unnamed module.
+        InputStream in = Main.class.getResourceAsStream("/" + NAME);
+        assertNotNull(in);
+
+        in = Main.class.getResourceAsStream("/p1/" + NAME);
+        assertNull(in);
+
+        in = Main.class.getResourceAsStream("/p1/impl/" + NAME);
+        assertNull(in);
+
+        in = Main.class.getResourceAsStream("/p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = Main.class.getResourceAsStream("/p2/" + NAME);
+        assertNull(in);
+
+        in = Main.class.getResourceAsStream("/p2/impl/" + NAME);
+        assertNull(in);
+
+        in = Main.class.getResourceAsStream("/p2/resources/" + NAME);
+        assertNull(in);
+
+
+        // invoke Class getResourceAsStream from module m1
+        in = p1.Main.getResourceAsStream("/" + NAME);
+        assertEquals(readAllAsString(in), "m1");
+
+        in = p1.Main.getResourceAsStream("/p1/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1");
+
+        in = p1.Main.getResourceAsStream("/p1/impl/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.impl");
+
+        in = p1.Main.getResourceAsStream("/p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = p1.Main.getResourceAsStream(p2.Main.class, "/" + NAME);
+        assertEquals(readAllAsString(in), "m2");
+
+        in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/" + NAME);
+        assertNull(in);
+
+        in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/impl/" + NAME);
+        assertNull(in);
 
-        // invoke Class getResourceAsStream from modules m1-m3
-        try (InputStream in = p1.Main.getResourceAsStream("/" + NAME)) {
-            String s = new String(in.readAllBytes(), "UTF-8");
-            assertEquals(s, "m1");
-        }
-        try (InputStream in = p2.Main.getResourceAsStream("/" + NAME)) {
-            String s = new String(in.readAllBytes(), "UTF-8");
-            assertEquals(s, "m2");
-        }
-        InputStream in3 = p3.Main.getResourceAsStream("/" + NAME);
-        assertNull(in3);
+        in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m2/p2.resources");
+
+
+        // invoke Class getResourceAsStream from module m2
+        in = p2.Main.getResourceAsStream("/" + NAME);
+        assertEquals(readAllAsString(in), "m2");
+
+        in = p2.Main.getResourceAsStream("/p2/" + NAME);
+        assertEquals(readAllAsString(in), "m2/p2");
+
+        in = p2.Main.getResourceAsStream("/p2/impl/" + NAME);
+        assertEquals(readAllAsString(in), "m2/p2.impl");
+
+        in = p2.Main.getResourceAsStream("/p2/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m2/p2.resources");
+
+        in = p2.Main.getResourceAsStream(p1.Main.class, "/" + NAME);
+        assertEquals(readAllAsString(in), "m1");
+
+        in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/" + NAME);
+        assertNull(in);
 
-        // invoke Module getResources on modules m1-m3
-        InputStream in1 = p1.Main.class.getModule().getResourceAsStream("/" + NAME);
-        InputStream in2 = p2.Main.class.getModule().getResourceAsStream("/" + NAME);
-        in3 = p3.Main.class.getModule().getResourceAsStream("/" + NAME);
-        assertNotNull(in1);
-        assertNotNull(in2);
-        assertNull(in3);
+        in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/impl/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
 
-        // check the content of in1 and in2
-        String s1 = new String(in1.readAllBytes(), "UTF-8");
-        String s2 = new String(in2.readAllBytes(), "UTF-8");
-        assertEquals(s1, "m1");
-        assertEquals(s2, "m2");
+        // Nulls
+        try {
+            Main.class.getResource(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+        try {
+            Main.class.getResourceAsStream(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+        try {
+            p1.Main.class.getResource(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+        try {
+            p1.Main.class.getResourceAsStream(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
 
         // SecurityManager case
         System.setSecurityManager(new SecurityManager());
@@ -106,17 +235,24 @@
         assertNull(Main.class.getResource("/" + NAME));
         assertNull(p1.Main.getResource("/" + NAME));
         assertNull(p2.Main.getResource("/" + NAME));
-        assertNull(p3.Main.getResource("/" + NAME));
 
         assertNull(Main.class.getResourceAsStream("/" + NAME));
         assertNull(p1.Main.getResourceAsStream("/" + NAME));
         assertNull(p2.Main.getResourceAsStream("/" + NAME));
-        assertNull(p3.Main.getResourceAsStream("/" + NAME));
 
         System.out.println("Success!");
     }
 
     /**
+     * Create a resource in the sub-directory of the given exploded module
+     */
+    static void createResource(String mn, Path subdir, String msg) throws IOException {
+        Path dir = directoryFor(mn).resolve(subdir);
+        Path file = dir.resolve(NAME);
+        Files.write(file, msg.getBytes("UTF-8"));
+    }
+
+    /**
      * Returns the directory for the given module (by name).
      */
     static Path directoryFor(String name) {
@@ -130,12 +266,21 @@
         return dir;
     }
 
-    static byte[] readAll(URL url) throws IOException {
-        try (InputStream in = url.openStream()) {
-            return in.readAllBytes();
+    static String readAllAsString(InputStream in) throws IOException {
+        if (in == null)
+            return null;
+        try (in) {
+            return new String(in.readAllBytes(), "UTF-8");
         }
     }
 
+    static String readAllAsString(URL url) throws IOException {
+        if (url == null)
+            return null;
+        InputStream in = url.openStream();
+        return readAllAsString(url.openStream());
+    }
+
     static void assertTrue(boolean condition) {
         if (!condition) throw new RuntimeException();
     }
--- a/jdk/test/java/lang/Class/getResource/ResourcesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/getResource/ResourcesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -68,7 +68,7 @@
             .compile(Paths.get(TEST_SRC, "Main.java"),
                      CLASSES_DIR,
                      "--module-path", MODS_DIR.toString(),
-                     "--add-modules", "m1,m2,m3");
+                     "--add-modules", "m1,m2");
         assertTrue(compiled);
 
     }
@@ -80,7 +80,7 @@
 
         int exitValue
             = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "--add-modules", "m1,m2,m3",
+                              "--add-modules", "m1,m2",
                                "-cp", CLASSES_DIR.toString(),
                               "Main")
                 .outputTo(System.out)
--- a/jdk/test/java/lang/Class/getResource/src/m1/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/getResource/src/m1/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,4 +23,5 @@
 
 module m1 {
     exports p1;
+    opens p1.resources;
 }
--- a/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -36,4 +36,12 @@
     public static InputStream getResourceAsStream(String name) {
         return Main.class.getResourceAsStream(name);
     }
+
+    public static URL getResource(Class<?> c, String name) {
+        return c.getResource(name);
+    }
+
+    public static InputStream getResourceAsStream(Class<?> c, String name) {
+        return c.getResourceAsStream(name);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/impl/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p1.impl;
+
+public class Type { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/resources/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p1.resources;
+
+public class Type { }
--- a/jdk/test/java/lang/Class/getResource/src/m2/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/getResource/src/m2/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,4 +23,6 @@
 
 module m2 {
     exports p2;
+    exports p2.impl to m1;
+    opens p2.resources to m1;
 }
--- a/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -36,4 +36,12 @@
     public static InputStream getResourceAsStream(String name) {
         return Main.class.getResourceAsStream(name);
     }
+
+    public static URL getResource(Class<?> c, String name) {
+        return c.getResource(name);
+    }
+
+    public static InputStream getResourceAsStream(Class<?> c, String name) {
+        return c.getResourceAsStream(name);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/impl/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p2.impl;
+
+public class Type { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/resources/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p2.resources;
+
+public class Type { }
--- a/jdk/test/java/lang/Class/getResource/src/m3/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module m3 {
-    exports p3;
-}
--- a/jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package p3;
-
-import java.io.InputStream;
-import java.net.URL;
-
-public class Main {
-    private Main() { }
-
-    public static URL getResource(String name) {
-        return Main.class.getResource(name);
-    }
-
-    public static InputStream getResourceAsStream(String name) {
-        return Main.class.getResourceAsStream(name);
-    }
-}
--- a/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,7 @@
  *          Quoted entries should get unquoted on Windows.
  *          Empty entries should be replaced with dot.
  * @library /lib/testlibrary
+ * @modules java.base/java.lang:open
  * @build jdk.testlibrary.Platform
  * @run main LibraryPathProperty
  */
--- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -106,6 +106,7 @@
 # run test
 ${TESTJAVA}${FS}bin${FS}java \
         ${TESTVMOPTS} \
+        --add-opens java.base/java.lang=ALL-UNNAMED \
         -verbose:class -Xlog:class+load -cp . \
         -Dtest.classes=${TESTCLASSES} \
         Starter cross
--- a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -102,6 +102,7 @@
 # run test
 ${TESTJAVA}${FS}bin${FS}java \
         ${TESTVMOPTS} \
+        --add-opens java.base/java.lang=ALL-UNNAMED \
         -verbose:class -Xlog:class+load -cp . \
         -Dtest.classes=${TESTCLASSES} \
         Starter one-way
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -21,13 +21,18 @@
  * questions.
  */
 
+import java.io.InputStream;
 import java.lang.module.Configuration;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
 import java.io.IOException;
+import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
 
 /**
  * Basic test of ClassLoader getResource and getResourceAsStream when
@@ -40,36 +45,242 @@
 
     public static void main(String[] args) throws IOException {
 
-        // create m1/myresource containing "m1"
-        Path file = directoryFor("m1").resolve(NAME);
-        Files.write(file, "m1".getBytes("UTF-8"));
+        // create resources in m1
+        createResource("m1", Paths.get("."), "m1");
+        createResource("m1", Paths.get("p1"), "m1/p1");
+        createResource("m1", Paths.get("p1", "impl"), "m1/p1.impl");
+        createResource("m1", Paths.get("p1", "resources"), "m1/p1.resources");
 
-        // create m2/myresource containing "m2"
-        file = directoryFor("m2").resolve(NAME);
-        Files.write(file, "m2".getBytes("UTF-8"));
+        // create resources in m2
+        createResource("m2", Paths.get("."), "m2");
+        createResource("m2", Paths.get("p2"), "m2/p2");
+        createResource("m2", Paths.get("p2", "impl"), "m2/p2.impl");
+        createResource("m2", Paths.get("p2", "resources"), "m2/p2.resources");
 
-        // check that m3/myresource does not exist
-        assertTrue(Files.notExists(directoryFor("m3").resolve(NAME)));
 
         // invoke ClassLoader getResource from the unnamed module
-        assertNull(Main.class.getClassLoader().getResource("/" + NAME));
+        ClassLoader thisLoader = Main.class.getClassLoader();
+
+        URL url = thisLoader.getResource(NAME);
+        assertNotNull(url);
+
+        url = thisLoader.getResource("p1/" + NAME);
+        assertNull(url);
+
+        url = thisLoader.getResource("p1/impl/" + NAME);
+        assertNull(url);
+
+        url = thisLoader.getResource("p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        url = thisLoader.getResource("p2/" + NAME);
+        assertNull(url);
+
+        url = thisLoader.getResource("p2/impl/" + NAME);
+        assertNull(url);
+
+        url = thisLoader.getResource("p2/resources/" + NAME);
+        assertNull(url);
+
+
+        // invoke ClassLoader getResource from module m1
+        url = p1.Main.getResourceInClassLoader(NAME);
+        assertNotNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p1/" + NAME);
+        assertNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p1/impl/" + NAME);
+        assertNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        url = p1.Main.getResourceInClassLoader("p2/" + NAME);
+        assertNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p2/impl/" + NAME);
+        assertNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p2/resources/" + NAME);
+        assertNull(url);
+
+
+        // invoke ClassLoader getResource from module m2
+        url = p2.Main.getResourceInClassLoader(NAME);
+        assertNotNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p1/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p1/impl/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        url = p2.Main.getResourceInClassLoader("p2/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p2/impl/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p2/resources/" + NAME);
+        assertNull(url);
+
+
+        // invoke ClassLoader getResources from the unnamed module
+        Enumeration<URL> urls = thisLoader.getResources(NAME);
+        List<String> resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 2);
+        assertTrue(resources.contains("m1"));
+        assertTrue(resources.contains("m2"));
 
-        // invoke ClassLoader getResource from modules m1-m3
-        // Resources in a named module are private to that module.
-        // ClassLoader.getResource should not find resource in named modules.
-        assertNull(p1.Main.getResourceInClassLoader("/" + NAME));
-        assertNull(p2.Main.getResourceInClassLoader("/" + NAME));
-        assertNull(p3.Main.getResourceInClassLoader("/" + NAME));
+        urls = thisLoader.getResources("p1/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = thisLoader.getResources("p1/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = thisLoader.getResources("p1/resources/" + NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 1);
+        assertTrue(resources.contains("m1/p1.resources"));
+
+        urls = thisLoader.getResources("p2/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = thisLoader.getResources("p2/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = thisLoader.getResources("p2/resources/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+
+        // invoke ClassLoader getResources from m1
+        urls = p1.Main.getResourcesInClassLoader(NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 2);
+        assertTrue(resources.contains("m1"));
+        assertTrue(resources.contains("m2"));
+
+        urls = p1.Main.getResourcesInClassLoader("p1/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p1.Main.getResourcesInClassLoader("p1/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p1.Main.getResourcesInClassLoader("p1/resources/" + NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 1);
+        assertTrue(resources.contains("m1/p1.resources"));
+
+        urls = p1.Main.getResourcesInClassLoader("p2/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p1.Main.getResourcesInClassLoader("p2/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p1.Main.getResourcesInClassLoader("p2/resources/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+
+        // invoke ClassLoader getResources from m2
+        urls = p2.Main.getResourcesInClassLoader(NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 2);
+        assertTrue(resources.contains("m1"));
+        assertTrue(resources.contains("m2"));
+
+        urls = p2.Main.getResourcesInClassLoader("p1/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p2.Main.getResourcesInClassLoader("p1/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p2.Main.getResourcesInClassLoader("p1/resources/" + NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 1);
+        assertTrue(resources.contains("m1/p1.resources"));
+
+        urls = p2.Main.getResourcesInClassLoader("p2/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p2.Main.getResourcesInClassLoader("p2/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p2.Main.getResourcesInClassLoader("p2/resources/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
 
         // invoke ClassLoader getResourceAsStream from the unnamed module
-        assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME));
+        InputStream in = thisLoader.getResourceAsStream(NAME);
+        assertNotNull(in);
+
+        in = thisLoader.getResourceAsStream("p1/" + NAME);
+        assertNull(in);
+
+        in = thisLoader.getResourceAsStream("p1/impl/" + NAME);
+        assertNull(in);
+
+        in = thisLoader.getResourceAsStream("p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = thisLoader.getResourceAsStream("p2/" + NAME);
+        assertNull(in);
+
+        in = thisLoader.getResourceAsStream("p2/impl/" + NAME);
+        assertNull(in);
+
+        in = thisLoader.getResourceAsStream("p2/resources/" + NAME);
+        assertNull(in);
+
+
+        // invoke ClassLoader getResource from modules m1
+        in = p1.Main.getResourceAsStreamInClassLoader(NAME);
+        assertNotNull(in);
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p1/" + NAME);
+        assertNull(in);
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p1/impl/" + NAME);
+        assertNull(in);
 
-        // invoke ClassLoader getResourceAsStream from modules m1-m3
-        // Resources in a named module are private to that module.
-        // ClassLoader.getResourceAsStream should not find resource in named modules.
-        assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME));
-        assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME));
-        assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        in = p1.Main.getResourceAsStreamInClassLoader("p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p2/" + NAME);
+        assertNull(in);
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p2/impl/" + NAME);
+        assertNull(in);
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p2/resources/" + NAME);
+        assertNull(in);
+
+
+        // invoke ClassLoader getResource from modules m2
+        in = p2.Main.getResourceAsStreamInClassLoader(NAME);
+        assertNotNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p1/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p1/impl/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p2/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p2/impl/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p2/resources/" + NAME);
+        assertNull(in);
+
 
         // SecurityManager case
         System.setSecurityManager(new SecurityManager());
@@ -77,17 +288,24 @@
         assertNull(Main.class.getClassLoader().getResource("/" + NAME));
         assertNull(p1.Main.getResourceInClassLoader("/" + NAME));
         assertNull(p2.Main.getResourceInClassLoader("/" + NAME));
-        assertNull(p3.Main.getResourceInClassLoader("/" + NAME));
 
         assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME));
         assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME));
         assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME));
-        assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME));
 
         System.out.println("Success!");
     }
 
     /**
+     * Create a resource in the sub-directory of the given exploded module
+     */
+    static void createResource(String mn, Path subdir, String msg) throws IOException {
+        Path dir = directoryFor(mn).resolve(subdir);
+        Path file = dir.resolve(NAME);
+        Files.write(file, msg.getBytes("UTF-8"));
+    }
+
+    /**
      * Returns the directory for the given module (by name).
      */
     static Path directoryFor(String mn) {
@@ -101,12 +319,60 @@
         return dir;
     }
 
+    static String readAllAsString(InputStream in) throws IOException {
+        if (in == null)
+            return null;
+        try (in) {
+            return new String(in.readAllBytes(), "UTF-8");
+        }
+    }
+
+    static String readAllAsString(URL url) throws IOException {
+        if (url == null)
+            return null;
+        InputStream in = url.openStream();
+        return readAllAsString(url.openStream());
+    }
+
+    static List<String> readAllAsStrings(Enumeration<URL> urls) throws IOException {
+        List<String> result = new ArrayList<>();
+        while (urls.hasMoreElements()) {
+            URL url = urls.nextElement();
+            result.add(readAllAsString(url));
+        }
+        return result;
+    }
+
     static void assertTrue(boolean condition) {
         if (!condition) throw new RuntimeException();
     }
 
+    static void assertFalse(boolean condition) {
+        if (condition) throw new RuntimeException();
+    }
+
     static void assertNull(Object o) {
         assertTrue(o == null);
     }
+
+    static void assertNotNull(Object o) {
+        assertTrue(o != null);
+    }
+
+    static void assertEquals(Object actual, Object expected) {
+        if (expected == null) {
+            assertNull(actual);
+        } else {
+            assertTrue(expected.equals(actual));
+        }
+    }
+
+    static void assertNotEquals(Object actual, Object expected) {
+        if (expected == null) {
+            assertNotNull(actual);
+        } else {
+            assertTrue(!expected.equals(actual));
+        }
+    }
 }
 
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -68,7 +68,7 @@
             .compile(Paths.get(TEST_SRC, "Main.java"),
                      CLASSES_DIR,
                      "--module-path", MODS_DIR.toString(),
-                     "--add-modules", "m1,m2,m3");
+                     "--add-modules", "m1,m2");
         assertTrue(compiled);
     }
 
@@ -78,7 +78,7 @@
     public void runTest() throws Exception {
         int exitValue
             = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "--add-modules", "m1,m2,m3",
+                              "--add-modules", "m1,m2",
                                "-cp", CLASSES_DIR.toString(),
                               "Main")
                 .outputTo(System.out)
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,4 +23,5 @@
 
 module m1 {
     exports p1;
+    opens p1.resources;
 }
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,9 @@
 package p1;
 
 import java.io.InputStream;
+import java.io.IOException;
 import java.net.URL;
+import java.util.Enumeration;
 
 public class Main {
     private Main() { }
@@ -33,6 +35,10 @@
         return Main.class.getClassLoader().getResource(name);
     }
 
+    public static Enumeration<URL> getResourcesInClassLoader(String name) throws IOException {
+        return Main.class.getClassLoader().getResources(name);
+    }
+
     public static InputStream getResourceAsStreamInClassLoader(String name) {
         return Main.class.getClassLoader().getResourceAsStream(name);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/impl/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p1.impl;
+
+public class Type { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/resources/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p1.resources;
+
+public class Type { }
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,4 +23,6 @@
 
 module m2 {
     exports p2;
+    exports p2.impl to m1;
+    opens p2.resources to m1;
 }
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,9 @@
 package p2;
 
 import java.io.InputStream;
+import java.io.IOException;
 import java.net.URL;
+import java.util.Enumeration;
 
 public class Main {
     private Main() { }
@@ -33,6 +35,10 @@
         return Main.class.getClassLoader().getResource(name);
     }
 
+    public static Enumeration<URL> getResourcesInClassLoader(String name) throws IOException {
+        return Main.class.getClassLoader().getResources(name);
+    }
+
     public static InputStream getResourceAsStreamInClassLoader(String name) {
         return Main.class.getClassLoader().getResourceAsStream(name);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/impl/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p2.impl;
+
+public class Type { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/resources/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p2.resources;
+
+public class Type { }
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module m3 {
-    exports p3;
-}
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package p3;
-
-import java.io.InputStream;
-import java.net.URL;
-
-public class Main {
-    private Main() { }
-
-    public static URL getResourceInClassLoader(String name) {
-        return Main.class.getClassLoader().getResource(name);
-    }
-
-    public static InputStream getResourceAsStreamInClassLoader(String name) {
-        return Main.class.getClassLoader().getResourceAsStream(name);
-    }
-}
--- a/jdk/test/java/lang/ProcessBuilder/Basic.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ProcessBuilder/Basic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
  *      4947220 7018606 7034570 4244896 5049299 8003488 8054494 8058464
  *      8067796
  * @summary Basic tests for Process and Environment Variable code
+ * @modules java.base/java.lang:open
  * @run main/othervm/timeout=300 Basic
  * @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=fork Basic
  * @author Martin Buchholz
--- a/jdk/test/java/lang/Runtime/Version/VersionProps.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/Runtime/Version/VersionProps.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 8160564
  * @summary check the implementation of VersionProps.versionNumbers()
+ * @modules java.base/java.lang:open
  * @run main VersionProps
  * @author Volker Simonis
  */
--- a/jdk/test/java/lang/StackWalker/CountLocalSlots.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/StackWalker/CountLocalSlots.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 8147039
  * @summary Confirm locals[] always has expected length, even for "dead" locals
+ * @modules java.base/java.lang:open
  * @compile LocalsAndOperands.java
  * @run testng/othervm -Xcomp CountLocalSlots
  */
--- a/jdk/test/java/lang/StackWalker/LocalsAndOperands.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/StackWalker/LocalsAndOperands.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 8020968 8147039
  * @summary Tests for locals and operands
+ * @modules java.base/java.lang:open
  * @run testng LocalsAndOperands
  */
 
--- a/jdk/test/java/lang/StackWalker/LocalsCrash.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/StackWalker/LocalsCrash.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 8147039
  * @summary Test for -Xcomp crash that happened before 8147039 fix
+ * @modules java.base/java.lang:open
  * @run testng/othervm -Xcomp LocalsCrash
  */
 
--- a/jdk/test/java/lang/String/CompactString/VMOptionsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/String/CompactString/VMOptionsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -37,6 +37,7 @@
  *          if Compact String enable/disable VM Options is indeed working in String class,
  *          it's verified by testing if the VM option affect coder and
  *          COMPACT_STRINGS field in String class.
+ * @modules java.base/java.lang:open
  * @run testng/othervm -XX:+CompactStrings -DCompactStringEnabled=true VMOptionsTest
  * @run testng/othervm -XX:-CompactStrings -DCompactStringEnabled=false VMOptionsTest
  */
--- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -39,7 +39,7 @@
  * @bug     8144460 8144214
  * @summary Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger
  *          and logXX APIs of SimpleConsoleLogger.
- * @modules java.base/jdk.internal.logger
+ * @modules java.base/jdk.internal.logger:+open
  *          java.base/sun.util.logging
  * @build BootstrapLoggerUtils LogStream
  * @run main/othervm BootstrapLoggerAPIsTest
--- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -52,7 +52,7 @@
  * @summary JDK implementation specific unit test for JDK internal artifacts.
             Tests the behavior of bootstrap loggers (and SimpleConsoleLoggers
  *          too).
- * @modules java.base/jdk.internal.logger
+ * @modules java.base/jdk.internal.logger:+open
  *          java.logging
  * @build BootstrapLoggerUtils LogStream
  * @run main/othervm BootstrapLoggerTest NO_SECURITY
--- a/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,6 +34,7 @@
  * @test 8163162
  * @summary Checks that LazyLoggers are returned for System.Logger instances
  *          created by modules in the platform class loader.
+ * @modules java.base/java.lang:open
  * @build systempkg.log.SystemLoggerAccessor SystemLoggerInPlatformLoader
  * @run main/othervm SystemLoggerInPlatformLoader
  * @author danielfuchs
--- a/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,7 +38,8 @@
  *           It calls both the {@link java.lang.System} factory methods and
  *           {@link jdk.internal.logger.LazyLoggers} to obtains those loggers,
  *           and configure them with all possible known levels.
- * @modules java.base/sun.util.logging
+ * @modules java.base/java.lang:open
+ *          java.base/sun.util.logging
  *          java.base/jdk.internal.logger
  *          java.logging/sun.util.logging.internal
  * @build LoggerFinderBackendTest SystemClassLoader
--- a/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,8 @@
  * @summary Test inheritance, order and class redefinition behaviour of RUNTIME
  *          class annotations
  * @author plevart
- * @modules java.base/sun.reflect.annotation
+ * @modules java.base/java.lang:open
+ *          java.base/sun.reflect.annotation
  */
 
 import sun.reflect.annotation.AnnotationParser;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/RedefineModuleAgent.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Module;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Agent used by RedefineModuleTest
+ */
+
+public class RedefineModuleAgent {
+
+    private static Instrumentation inst;
+
+    public static void premain(String args, Instrumentation inst) throws Exception {
+        RedefineModuleAgent.inst = inst;
+    }
+
+    static void redefineModule(Module module,
+                               Set<Module> extraReads,
+                               Map<String, Set<Module>> extraExports,
+                               Map<String, Set<Module>> extraOpens,
+                               Set<Class<?>> extraUses,
+                               Map<Class<?>, List<Class<?>>> extraProvides) {
+        inst.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/RedefineModuleTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,369 @@
+/*
+ * 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 Basic test for redefineModule
+ * @modules java.instrument
+ * @build java.base/java.lang.TestProvider
+ *        java.base/jdk.internal.test.TestProviderImpl1
+ *        java.base/jdk.internal.test.TestProviderImpl2
+ * @run shell MakeJAR3.sh RedefineModuleAgent
+ * @run testng/othervm -javaagent:RedefineModuleAgent.jar RedefineModuleTest
+ */
+
+import java.lang.TestProvider;
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.net.URLStreamHandler;
+import java.net.spi.URLStreamHandlerProvider;
+import java.nio.file.FileSystems;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class RedefineModuleTest {
+
+    static void redefineModule(Module module,
+                               Set<Module> extraReads,
+                               Map<String, Set<Module>> extraExports,
+                               Map<String, Set<Module>> extraOpens,
+                               Set<Class<?>> extraUses,
+                               Map<Class<?>, List<Class<?>>> extraProvides) {
+        RedefineModuleAgent.redefineModule(module,
+                                           extraReads,
+                                           extraExports,
+                                           extraOpens,
+                                           extraUses,
+                                           extraProvides);
+    }
+
+
+    /**
+     * Use redefineModule to update java.base to read java.instrument
+     */
+    public void testAddReads() {
+        Module baseModule = Object.class.getModule();
+        Module instrumentModule = Instrumentation.class.getModule();
+
+        // pre-conditions
+        assertFalse(baseModule.canRead(instrumentModule));
+
+        // update java.base to read java.instrument
+        Set<Module> extraReads = Set.of(instrumentModule);
+        redefineModule(baseModule, extraReads, Map.of(), Map.of(), Set.of(), Map.of());
+        assertTrue(baseModule.canRead(instrumentModule));
+    }
+
+    /**
+     * Use redefineModule to update java.base to export jdk.internal.misc
+     */
+    public void testAddExports() {
+        Module baseModule = Object.class.getModule();
+        Module thisModule = this.getClass().getClassLoader().getUnnamedModule();
+        String pkg = "jdk.internal.misc";
+
+        // pre-conditions
+        assertFalse(baseModule.isExported(pkg));
+        assertFalse(baseModule.isExported(pkg, thisModule));
+
+        // update java.base to export jdk.internal.misc to an unnamed module
+        Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of(thisModule));
+        redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+        assertFalse(baseModule.isExported(pkg));
+        assertTrue(baseModule.isExported(pkg, thisModule));
+        assertFalse(baseModule.isOpen(pkg));
+        assertFalse(baseModule.isOpen(pkg, thisModule));
+    }
+
+    /**
+     * Use redefineModule to update java.base to open jdk.internal.loader
+     */
+    public void testAddOpens() {
+        Module baseModule = Object.class.getModule();
+        Module thisModule = this.getClass().getClassLoader().getUnnamedModule();
+        String pkg = "jdk.internal.loader";
+
+        // pre-conditions
+        assertFalse(baseModule.isOpen(pkg));
+        assertFalse(baseModule.isOpen(pkg, thisModule));
+
+        // update java.base to open dk.internal.loader to an unnamed module
+        Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of(thisModule));
+        redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of());
+        assertFalse(baseModule.isExported(pkg));
+        assertTrue(baseModule.isExported(pkg, thisModule));
+        assertFalse(baseModule.isOpen(pkg));
+        assertTrue(baseModule.isOpen(pkg, thisModule));
+    }
+
+    /**
+     * Use redefineModule to update java.base to use TestProvider and
+     * provide implementations of TestProvider.
+     */
+    public void testAddUsesAndProvides() throws Exception {
+        Module baseModule = Object.class.getModule();
+        Class<TestProvider> service = TestProvider.class;
+
+        // pre-conditions
+        assertFalse(baseModule.canUse(service));
+        assertTrue(collect(ServiceLoader.load(service)).isEmpty());
+        assertTrue(collect(ServiceLoader.load(Layer.boot(), service)).isEmpty());
+
+        // update java.base to use TestProvider
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(service), Map.of());
+        assertTrue(baseModule.canUse(service));
+        assertTrue(collect(ServiceLoader.load(service)).isEmpty());
+        assertTrue(collect(ServiceLoader.load(Layer.boot(), service)).isEmpty());
+
+        // update java.base to provide an implementation of TestProvider
+        Class<?> type1 = Class.forName("jdk.internal.test.TestProviderImpl1");
+        Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of(type1));
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+
+        // invoke ServiceLoader from java.base to find providers
+        Set<TestProvider> providers = collect(TestProvider.providers());
+        assertTrue(providers.size() == 1);
+        assertTrue(containsInstanceOf(providers, type1));
+
+        // use ServiceLoader to load implementations visible via TCCL
+        providers = collect(ServiceLoader.load(service));
+        assertTrue(collect(providers).size() == 1);
+        assertTrue(containsInstanceOf(collect(providers), type1));
+
+        // use ServiceLoader to load implementations in the boot layer
+        providers = collect(ServiceLoader.load(Layer.boot(), service));
+        assertTrue(collect(providers).size() == 1);
+        assertTrue(containsInstanceOf(collect(providers), type1));
+
+        // update java.base to provide a second implementation of TestProvider
+        Class<?> type2 = Class.forName("jdk.internal.test.TestProviderImpl2");
+        extraProvides = Map.of(service, List.of(type2));
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+
+        // invoke ServiceLoader from java.base to find providers
+        providers = collect(TestProvider.providers());
+        assertTrue(providers.size() == 2);
+        assertTrue(containsInstanceOf(providers, type1));
+        assertTrue(containsInstanceOf(providers, type2));
+
+        // use ServiceLoader to load implementations visible via TCCL
+        providers = collect(ServiceLoader.load(service));
+        assertTrue(collect(providers).size() == 2);
+        assertTrue(containsInstanceOf(providers, type1));
+        assertTrue(containsInstanceOf(providers, type2));
+
+        // use ServiceLoader to load implementations in the boot layer
+        providers = collect(ServiceLoader.load(Layer.boot(), service));
+        assertTrue(collect(providers).size() == 2);
+        assertTrue(containsInstanceOf(providers, type1));
+        assertTrue(containsInstanceOf(providers, type2));
+    }
+
+    private <S> Set<S> collect(Iterable<S> sl) {
+        Set<S> providers = new HashSet<>();
+        sl.forEach(providers::add);
+        return providers;
+    }
+
+    private boolean containsInstanceOf(Collection<?> c, Class<?> type) {
+        for (Object o : c) {
+            if (type.isInstance(o)) return true;
+        }
+        return false;
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testExportPackageToEmptySet() {
+        // attempt to update java.base to export jdk.internal.misc to nobody
+        Module baseModule = Object.class.getModule();
+        Map<String, Set<Module>> extraExports = Map.of("jdk.internal.misc", Set.of());
+        redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testOpenPackageToEmptySet() {
+        // attempt to update java.base to open jdk.internal.misc to nobody
+        Module baseModule = Object.class.getModule();
+        Map<String, Set<Module>> extraOpens = Map.of("jdk.internal.misc", Set.of());
+        redefineModule(baseModule, Set.of(), Map.of(), extraOpens, Set.of(), Map.of());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testProvideServiceWithEmptyList() throws Exception {
+        // update java.base to provide an empty list of TestProvider
+        Module baseModule = Object.class.getModule();
+        Class<?> service = TestProvider.class;
+        Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of());
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+    }
+
+    /**
+     * Test redefineClass by attempting to update java.base to export a package
+     * that it does not contain.
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testExportPackageNotInModule() {
+        Module baseModule = Object.class.getModule();
+        String pkg = "jdk.doesnotexist";
+
+        // attempt to update java.base to export jdk.doesnotexist
+        Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of());
+        redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+    }
+
+    /**
+     * Test redefineClass by attempting to update java.base to provide a service
+     * where the service provider class is not in the module.
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testProvideServiceNotInModule() {
+        Module baseModule = Object.class.getModule();
+        class MyProvider extends URLStreamHandlerProvider {
+            @Override
+            public URLStreamHandler createURLStreamHandler(String protocol) {
+                return null;
+            }
+        }
+
+        // attempt to update java.base to provide MyProvider
+        Map<Class<?>, List<Class<?>>> extraProvides
+            = Map.of(URLStreamHandlerProvider.class, List.of(MyProvider.class));
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+    }
+
+    /**
+     * Test redefineClass by attempting to update java.base to provide a
+     * service where the service provider class is not a sub-type.
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testProvideServiceNotSubtype() {
+        Module baseModule = Object.class.getModule();
+
+        Class<?> service = TestProvider.class;
+        Class<?> impl = FileSystems.getDefault().provider().getClass();
+
+        // attempt to update java.base to provide an implementation of TestProvider
+        Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of(impl));
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+    }
+
+    /**
+     * Test redefineClass with null
+     */
+    public void testNulls() {
+        Module baseModule = Object.class.getModule();
+
+        try {
+            redefineModule(null, Set.of(), Map.of(), Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, null, Map.of(), Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, Set.of(), null, Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, Set.of(), Map.of(), null, Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), null, Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), null);
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Set<Module> containsNull = new HashSet<>();
+            containsNull.add(null);
+            redefineModule(baseModule, containsNull, Map.of(), Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Map<String, Set<Module>> extraExports = new HashMap<>();
+            extraExports.put(null, Set.of());
+            redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Map<String, Set<Module>> extraExports = new HashMap<>();
+            extraExports.put(null, Set.of());
+            redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Set<Module> containsNull = new HashSet<>();
+            containsNull.add(null);
+            Map<String, Set<Module>> extraExports = Map.of("java.lang", containsNull);
+            redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Set<Class<?>> containsNull = new HashSet<>();
+            containsNull.add(null);
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), containsNull, Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Map<Class<?>, List<Class<?>>> extraProvides = new HashMap<>();
+            extraProvides.put(null, List.of());
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            List<Class<?>> containsNull = new ArrayList<>();
+            containsNull.add(null);
+            Map<Class<?>, List<Class<?>>> extraProvides = Map.of(TestProvider.class, containsNull);
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+    }
+
+}
--- a/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,7 @@
  * the module graph
  * @modules java.instrument
  * @run shell MakeJAR3.sh SimpleAgent
- * @run main/othervm -javaagent:SimpleAgent.jar -limitmods java.base TestAgentWithLimitMods
+ * @run main/othervm -javaagent:SimpleAgent.jar --limit-modules java.base TestAgentWithLimitMods
  *
  */
 public class TestAgentWithLimitMods {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/java.base/java/lang/TestProvider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package java.lang;
+
+import java.util.ServiceLoader;
+
+public interface TestProvider {
+    public static Iterable<TestProvider> providers() {
+        return ServiceLoader.load(TestProvider.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl1.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package jdk.internal.test;
+
+import java.lang.TestProvider;
+
+public class TestProviderImpl1 implements TestProvider {
+    public TestProviderImpl1() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl2.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package jdk.internal.test;
+
+import java.lang.TestProvider;
+
+public class TestProviderImpl2 implements TestProvider {
+    public TestProviderImpl2() { }
+}
+
--- a/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,7 +28,9 @@
  * @summary Test verifies that lambda forms are cached when run with multiple threads
  * @author kshefov
  * @library /lib/testlibrary/jsr292 /lib/testlibrary
- * @modules jdk.management
+ * @modules java.base/java.lang.invoke:open
+ *          java.base/java.lang.ref:open
+ *          jdk.management
  * @build TestMethods
  * @build LambdaFormTestCase
  * @build LFCachingTestCase
--- a/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,8 @@
  * @summary Test verifies that lambda forms are cached when run with single thread
  * @author kshefov
  * @library /lib/testlibrary/jsr292 /lib/testlibrary
+ * @modules java.base/java.lang.ref:open
+ *          java.base/java.lang.invoke:open
  * @build TestMethods
  * @build LambdaFormTestCase
  * @build LFCachingTestCase
--- a/jdk/test/java/lang/invoke/LambdaFormTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/invoke/LambdaFormTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,7 @@
 
 /* @test
  * @summary unit tests for java.lang.invoke.LambdaForm
+ * @modules java.base/java.lang.invoke:open
  * @run junit/othervm test.java.lang.invoke.LambdaFormTest
  */
 package test.java.lang.invoke;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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
+ * @build test/* m1/* m2/* m3/*
+ * @run testng/othervm test/p.PrivateLookupInTests
+ * @summary Unit tests for MethodHandles.privateLookupIn
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+open module m1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/p1/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 p1;
+
+class Type {
+    private static final Object obj = new Object();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+module m2 {
+    opens p2 to test;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/p2/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 p2;
+
+class Type {
+    private static final Object obj = new Object();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+module m3 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/p3/Type.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 p3;
+
+class Type {
+    private static final Object obj = new Object();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+module test {
+   requires testng;
+   exports p to testng;   // TestNG invokes the public methods
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,189 @@
+/*
+ * 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 p;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
+
+import static java.lang.invoke.MethodHandles.Lookup.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * Unit tests for MethodHandles.privateLookupIn
+ */
+
+@Test
+public class PrivateLookupInTests {
+
+    /**
+     * A public and non-public types in the test module but in a different
+     * package to the test class.
+     *
+     * package p.internal;
+     * public class PublicType {
+     * }
+     *
+     * package p.internal;
+     * class NonPublicType {
+     *     private static final Object obj = ...
+     * }
+     */
+    private Class<?> publicType;
+    private Class<?> nonPublicType;
+
+    // initialize and sanity check publicType/nonPublicType
+    @BeforeTest
+    public void init() throws Exception {
+        publicType = Class.forName("p.internal.PublicType");
+        assertTrue(this.getClass().getModule() == publicType.getModule());
+        assertNotEquals(this.getClass().getPackageName(), publicType.getPackageName());
+        assertTrue(Modifier.isPublic(publicType.getModifiers()));
+
+        nonPublicType = Class.forName("p.internal.NonPublicType");
+        assertTrue(this.getClass().getModule() == nonPublicType.getModule());
+        assertNotEquals(this.getClass().getPackageName(), nonPublicType.getPackageName());
+        assertFalse(Modifier.isPublic(nonPublicType.getModifiers()));
+    }
+
+    // Invoke MethodHandles.privateLookupIn with a full-power caller
+    public void testAllAccessCallerSameModule() throws Throwable {
+        Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, MethodHandles.lookup());
+        assertTrue(lookup.lookupClass() == nonPublicType);
+        assertTrue(lookup.hasPrivateAccess());
+
+        // get obj field
+        MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class);
+        Object obj = mh.invokeExact();
+    }
+
+    // Invoke MethodHandles.privateLookupIn with a reduced-power caller
+    public void testReducedAccessCallerSameModule() throws Throwable {
+        // drop access
+        Lookup caller = MethodHandles.lookup().in(publicType);
+        assertTrue((caller.lookupModes() & PRIVATE) == 0);
+        assertTrue((caller.lookupModes() & PACKAGE) == 0);
+        assertTrue((caller.lookupModes() & MODULE) != 0);
+
+        Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller);
+        assertTrue(lookup.lookupClass() == nonPublicType);
+        assertTrue(lookup.hasPrivateAccess());
+
+        // use it
+        MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class);
+        Object obj = mh.invokeExact();
+    }
+
+    // Invoke MethodHandles.privateLookupIn with the public lookup as caller
+    @Test(expectedExceptions = {IllegalAccessException.class})
+    public void testPublicLookupSameModule() throws Exception {
+        Lookup caller = MethodHandles.publicLookup();
+        Lookup lookup = MethodHandles.privateLookupIn(publicType, caller);
+    }
+
+    // test reads m1, open module m1 containing p1
+    public void testTargetClassInOpenModule() throws Throwable {
+        // m1/p1.Type
+        Class<?> clazz = Class.forName("p1.Type");
+        assertEquals(clazz.getModule().getName(), "m1");
+
+        // ensure that this module reads m1
+        Module thisModule = getClass().getModule();
+        Module m1 = clazz.getModule();
+        thisModule.addReads(clazz.getModule());
+        assertTrue(m1.isOpen("p1", thisModule));
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        assertTrue(lookup.lookupClass() == clazz);
+        assertTrue(lookup.hasPrivateAccess());
+
+        // get obj field
+        MethodHandle mh = lookup.findStaticGetter(clazz, "obj", Object.class);
+        Object obj = mh.invokeExact();
+    }
+
+    // test does not read m2, m2 opens p2 to test
+    @Test(expectedExceptions = {IllegalAccessException.class})
+    public void testCallerDoesNotRead() throws Throwable {
+        // m2/p2.Type
+        Class<?> clazz = Class.forName("p2.Type");
+        assertEquals(clazz.getModule().getName(), "m2");
+
+        Module thisModule = getClass().getModule();
+        Module m2 = clazz.getModule();
+        assertFalse(thisModule.canRead(m2));
+        assertTrue(m2.isOpen("p2", thisModule));
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+    }
+
+    // test reads m3, m3 does not open p3 to test
+    @Test(expectedExceptions = {IllegalAccessException.class})
+    public void testNotOpenToCaller() throws Throwable {
+        // m3/p2.Type
+        Class<?> clazz = Class.forName("p3.Type");
+        assertEquals(clazz.getModule().getName(), "m3");
+
+        Module thisModule = getClass().getModule();
+        Module m3 = clazz.getModule();
+        thisModule.addReads(clazz.getModule());
+        assertFalse(m3.isOpen("p3", thisModule));
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with a primitive class
+    @Test(expectedExceptions = {IllegalArgumentException.class})
+    public void testPrimitiveClassAsTargetClass() throws Exception {
+        MethodHandles.privateLookupIn(int.class, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with an array class
+    @Test(expectedExceptions = {IllegalArgumentException.class})
+    public void testArrayClassAsTargetClass() throws Exception {
+        MethodHandles.privateLookupIn(PrivateLookupInTests[].class, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with a primitive array class
+    @Test(expectedExceptions = {IllegalArgumentException.class})
+    public void testPrimitiveArrayClassAsTargetClass() throws Exception {
+        MethodHandles.privateLookupIn(int[].class, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with null
+    @Test(expectedExceptions = {NullPointerException.class})
+    public void testNullTargetClass() throws Exception {
+        MethodHandles.privateLookupIn(null, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with null
+    @Test(expectedExceptions = {NullPointerException.class})
+    public void testNullCaller() throws Exception {
+        MethodHandles.privateLookupIn(getClass(), null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/NonPublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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 p.internal;
+
+class NonPublicType {
+    private static final Object obj = new Object();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/PublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,28 @@
+/*
+ * 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 p.internal;
+
+public class PublicType {
+}
+
--- a/jdk/test/java/lang/invoke/PrivateInvokeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/invoke/PrivateInvokeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,7 @@
 
 /* @test
  * @summary white-box testing of method handle sub-primitives
+ * @modules java.base/java.lang.invoke:open
  * @run junit test.java.lang.invoke.PrivateInvokeTest
  */
 
--- a/jdk/test/java/lang/invoke/VMAnonymousClass.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/invoke/VMAnonymousClass.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,7 +32,6 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
-import java.lang.reflect.Field;
 import org.junit.Test;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.org.objectweb.asm.*;
@@ -64,7 +63,7 @@
        throw new RuntimeException("Expected SecurityException");
      }
 
-    private static Unsafe unsafe = getUnsafe();
+    private static Unsafe unsafe = Unsafe.getUnsafe();
 
     private static void test(String pkg) throws Throwable {
         byte[] bytes = dumpClass(pkg);
@@ -130,14 +129,4 @@
         cw.visitEnd();
         return cw.toByteArray();
     }
-
-    private static synchronized Unsafe getUnsafe() {
-        try {
-            Field f = Unsafe.class.getDeclaredField("theUnsafe");
-            f.setAccessible(true);
-            return (Unsafe) f.get(null);
-        } catch (NoSuchFieldException | IllegalAccessException e) {
-            throw new RuntimeException("Unable to get Unsafe instance.", e);
-        }
-    }
 }
--- a/jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -127,8 +127,13 @@
                                "-Djdk.internal.lambda.dumpProxyClasses=dump",
                                "-Djava.security.manager",
                                "com.example.TestLambda");
-        // dump/com/example + 2 class files
-        assertEquals(Files.walk(Paths.get("dump")).count(), 5, "Two lambda captured");
+        // 2 our own class files. We don't care about the others
+        assertEquals(Files.find(
+                        Paths.get("dump"),
+                        99,
+                        (p, a) -> p.startsWith(Paths.get("dump/com/example"))
+                                && a.isRegularFile()).count(),
+                2, "Two lambda captured");
         tr.assertZero("Should still return 0");
     }
 
--- a/jdk/test/java/lang/module/AutomaticModulesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/module/AutomaticModulesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -67,6 +67,15 @@
             // JAR file name                module-name[/version]
 
             { "foo.jar",                    "foo" },
+            { "foo4j.jar",                  "foo4j", },
+
+            { "foo1.jar",                   "foo" },
+            { "foo1.2.jar",                 "foo" },
+            { "foo1.2.3.jar",               "foo" },
+
+            { "foo10.jar",                  "foo" },
+            { "foo10.20.jar",               "foo" },
+            { "foo10.20.30.jar",            "foo" },
 
             { "foo-1.jar",                  "foo/1" },
             { "foo-1.2.jar",                "foo/1.2" },
@@ -258,8 +267,8 @@
 
         ModuleDescriptor descriptor = mref.get().descriptor();
         assertTrue(descriptor.provides().size() == 1);
-        assertTrue(descriptor.provides().containsKey(service));
-        ModuleDescriptor.Provides provides = descriptor.provides().get(service);
+        ModuleDescriptor.Provides provides = descriptor.provides().iterator().next();
+        assertEquals(provides.service(), service);
         assertTrue(provides.providers().size() == 1);
         assertTrue(provides.providers().contains((provider)));
     }
@@ -343,17 +352,17 @@
         attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
 
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m1.jar"), man);
+        createDummyJarFile(dir.resolve("m.jar"), man);
 
         ModuleFinder finder = ModuleFinder.of(dir);
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1");
+        Configuration cf = resolve(parent, finder, "m");
 
-        ModuleDescriptor m1 = findDescriptor(cf, "m1");
+        ModuleDescriptor descriptor = findDescriptor(cf, "m");
 
-        assertTrue(m1.mainClass().isPresent());
-        assertEquals(m1.mainClass().get(), mainClass);
+        assertTrue(descriptor.mainClass().isPresent());
+        assertEquals(descriptor.mainClass().get(), mainClass);
     }
 
 
@@ -380,7 +389,7 @@
         attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
 
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m1.jar"), man);
+        createDummyJarFile(dir.resolve("m.jar"), man);
 
         // should throw FindException
         ModuleFinder.of(dir).findAll();
@@ -389,213 +398,213 @@
 
     /**
      * Basic test of a configuration created with automatic modules.
-     *   m1 requires m2*
-     *   m1 requires m3*
-     *   m2*
-     *   m3*
+     *   a requires b*
+     *   a requires c*
+     *   b*
+     *   c*
      */
     public void testConfiguration1() throws Exception {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .requires("m2")
-                .requires("m3")
+            = ModuleDescriptor.module("a")
+                .requires("b")
+                .requires("c")
                 .requires("java.base")
                 .build();
 
-        // m2 and m3 are automatic modules
+        // b and c are automatic modules
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m2.jar"), "p/T.class");
-        createDummyJarFile(dir.resolve("m3.jar"), "q/T.class");
+        createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
+        createDummyJarFile(dir.resolve("c.jar"), "q/T.class");
 
-        // module finder locates m1 and the modules in the directory
+        // module finder locates a and the modules in the directory
         ModuleFinder finder
             = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1),
                 ModuleFinder.of(dir));
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1");
+        Configuration cf = resolve(parent, finder, "a");
 
         assertTrue(cf.modules().size() == 3);
-        assertTrue(cf.findModule("m1").isPresent());
-        assertTrue(cf.findModule("m2").isPresent());
-        assertTrue(cf.findModule("m3").isPresent());
+        assertTrue(cf.findModule("a").isPresent());
+        assertTrue(cf.findModule("b").isPresent());
+        assertTrue(cf.findModule("c").isPresent());
 
         ResolvedModule base = cf.findModule("java.base").get();
         assertTrue(base.configuration() == Layer.boot().configuration());
-        ResolvedModule m1 = cf.findModule("m1").get();
-        ResolvedModule m2 = cf.findModule("m2").get();
-        ResolvedModule m3 = cf.findModule("m3").get();
+        ResolvedModule a = cf.findModule("a").get();
+        ResolvedModule b = cf.findModule("b").get();
+        ResolvedModule c = cf.findModule("c").get();
 
-        // m2 && m3 only require java.base
-        assertTrue(m2.reference().descriptor().requires().size() == 1);
-        assertTrue(m3.reference().descriptor().requires().size() == 1);
+        // b && c only require java.base
+        assertTrue(b.reference().descriptor().requires().size() == 1);
+        assertTrue(c.reference().descriptor().requires().size() == 1);
 
         // readability
 
-        assertTrue(m1.reads().size() == 3);
-        assertTrue(m1.reads().contains(base));
-        assertTrue(m1.reads().contains(m2));
-        assertTrue(m1.reads().contains(m3));
+        assertTrue(a.reads().size() == 3);
+        assertTrue(a.reads().contains(base));
+        assertTrue(a.reads().contains(b));
+        assertTrue(a.reads().contains(c));
 
-        assertTrue(m2.reads().contains(m1));
-        assertTrue(m2.reads().contains(m3));
-        testReadAllBootModules(cf, "m2");  // m2 reads all modules in boot layer
+        assertTrue(b.reads().contains(a));
+        assertTrue(b.reads().contains(c));
+        testReadAllBootModules(cf, "b");  // b reads all modules in boot layer
 
-        assertTrue(m3.reads().contains(m1));
-        assertTrue(m3.reads().contains(m2));
-        testReadAllBootModules(cf, "m3");  // m3 reads all modules in boot layer
+        assertTrue(c.reads().contains(a));
+        assertTrue(c.reads().contains(b));
+        testReadAllBootModules(cf, "c");  // c reads all modules in boot layer
 
     }
 
     /**
      * Basic test of a configuration created with automatic modules
-     *   m1 requires m2
-     *   m2 requires m3*
-     *   m3*
-     *   m4*
+     *   a requires b
+     *   b requires c*
+     *   c*
+     *   d*
      */
     public void testInConfiguration2() throws IOException {
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
-                .requires("m2")
+            = ModuleDescriptor.module("a")
+                .requires("b")
                 .requires("java.base")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .requires("m3")
+            = ModuleDescriptor.module("b")
+                .requires("c")
                 .requires("java.base")
                 .build();
 
-        // m3 and m4 are automatic modules
+        // c and d are automatic modules
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m3.jar"), "p/T.class");
-        createDummyJarFile(dir.resolve("m4.jar"), "q/T.class");
+        createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
+        createDummyJarFile(dir.resolve("d.jar"), "q/T.class");
 
-        // module finder locates m1 and the modules in the directory
+        // module finder locates a and the modules in the directory
         ModuleFinder finder
             = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2),
                                    ModuleFinder.of(dir));
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1", "m4");
+        Configuration cf = resolve(parent, finder, "a", "d");
 
         assertTrue(cf.modules().size() == 4);
-        assertTrue(cf.findModule("m1").isPresent());
-        assertTrue(cf.findModule("m2").isPresent());
-        assertTrue(cf.findModule("m3").isPresent());
-        assertTrue(cf.findModule("m4").isPresent());
+        assertTrue(cf.findModule("a").isPresent());
+        assertTrue(cf.findModule("b").isPresent());
+        assertTrue(cf.findModule("c").isPresent());
+        assertTrue(cf.findModule("d").isPresent());
 
-        // m3 && m4 should only require java.base
-        assertTrue(findDescriptor(cf, "m3").requires().size() == 1);
-        assertTrue(findDescriptor(cf, "m4").requires().size() == 1);
+        // c && d should only require java.base
+        assertTrue(findDescriptor(cf, "c").requires().size() == 1);
+        assertTrue(findDescriptor(cf, "d").requires().size() == 1);
 
         // readability
 
         ResolvedModule base = cf.findModule("java.base").get();
         assertTrue(base.configuration() == Layer.boot().configuration());
-        ResolvedModule m1 = cf.findModule("m1").get();
-        ResolvedModule m2 = cf.findModule("m2").get();
-        ResolvedModule m3 = cf.findModule("m3").get();
-        ResolvedModule m4 = cf.findModule("m4").get();
+        ResolvedModule a = cf.findModule("a").get();
+        ResolvedModule b = cf.findModule("b").get();
+        ResolvedModule c = cf.findModule("c").get();
+        ResolvedModule d = cf.findModule("d").get();
 
-        assertTrue(m1.reads().size() == 2);
-        assertTrue(m1.reads().contains(m2));
-        assertTrue(m1.reads().contains(base));
+        assertTrue(a.reads().size() == 2);
+        assertTrue(a.reads().contains(b));
+        assertTrue(a.reads().contains(base));
 
-        assertTrue(m2.reads().size() == 3);
-        assertTrue(m2.reads().contains(m3));
-        assertTrue(m2.reads().contains(m4));
-        assertTrue(m2.reads().contains(base));
+        assertTrue(b.reads().size() == 3);
+        assertTrue(b.reads().contains(c));
+        assertTrue(b.reads().contains(d));
+        assertTrue(b.reads().contains(base));
 
-        assertTrue(m3.reads().contains(m1));
-        assertTrue(m3.reads().contains(m2));
-        assertTrue(m3.reads().contains(m4));
-        testReadAllBootModules(cf, "m3");   // m3 reads all modules in boot layer
+        assertTrue(c.reads().contains(a));
+        assertTrue(c.reads().contains(b));
+        assertTrue(c.reads().contains(d));
+        testReadAllBootModules(cf, "c");   // c reads all modules in boot layer
 
-        assertTrue(m4.reads().contains(m1));
-        assertTrue(m4.reads().contains(m2));
-        assertTrue(m4.reads().contains(m3));
-        testReadAllBootModules(cf, "m4");    // m4 reads all modules in boot layer
+        assertTrue(d.reads().contains(a));
+        assertTrue(d.reads().contains(b));
+        assertTrue(d.reads().contains(c));
+        testReadAllBootModules(cf, "d");    // d reads all modules in boot layer
     }
 
 
     /**
      * Basic test of a configuration created with automatic modules
-     *   m1 requires m2
-     *   m2 requires public m3*
-     *   m3*
-     *   m4*
+     *   a requires b
+     *   b requires transitive c*
+     *   c*
+     *   d*
      */
     public void testInConfiguration3() throws IOException {
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
-                .requires("m2")
+            = ModuleDescriptor.module("a")
+                .requires("b")
                 .requires("java.base")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m3")
+            = ModuleDescriptor.module("b")
+                .requires(Set.of(Modifier.TRANSITIVE), "c")
                 .requires("java.base")
                 .build();
 
-        // m3 and m4 are automatic modules
+        // c and d are automatic modules
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m3.jar"), "p/T.class");
-        createDummyJarFile(dir.resolve("m4.jar"), "q/T.class");
+        createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
+        createDummyJarFile(dir.resolve("d.jar"), "q/T.class");
 
-        // module finder locates m1 and the modules in the directory
+        // module finder locates a and the modules in the directory
         ModuleFinder finder
             = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2),
                 ModuleFinder.of(dir));
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1", "m4");
+        Configuration cf = resolve(parent, finder, "a", "d");
 
         assertTrue(cf.modules().size() == 4);
-        assertTrue(cf.findModule("m1").isPresent());
-        assertTrue(cf.findModule("m2").isPresent());
-        assertTrue(cf.findModule("m3").isPresent());
-        assertTrue(cf.findModule("m4").isPresent());
+        assertTrue(cf.findModule("a").isPresent());
+        assertTrue(cf.findModule("b").isPresent());
+        assertTrue(cf.findModule("c").isPresent());
+        assertTrue(cf.findModule("d").isPresent());
 
         ResolvedModule base = cf.findModule("java.base").get();
         assertTrue(base.configuration() == Layer.boot().configuration());
-        ResolvedModule m1 = cf.findModule("m1").get();
-        ResolvedModule m2 = cf.findModule("m2").get();
-        ResolvedModule m3 = cf.findModule("m3").get();
-        ResolvedModule m4 = cf.findModule("m4").get();
+        ResolvedModule a = cf.findModule("a").get();
+        ResolvedModule b = cf.findModule("b").get();
+        ResolvedModule c = cf.findModule("c").get();
+        ResolvedModule d = cf.findModule("d").get();
 
-        // m3 && m4 should only require java.base
-        assertTrue(findDescriptor(cf, "m3").requires().size() == 1);
-        assertTrue(findDescriptor(cf, "m4").requires().size() == 1);
+        // c && d should only require java.base
+        assertTrue(findDescriptor(cf, "c").requires().size() == 1);
+        assertTrue(findDescriptor(cf, "d").requires().size() == 1);
 
         // readability
 
-        assertTrue(m1.reads().size() == 4);
-        assertTrue(m1.reads().contains(m2));
-        assertTrue(m1.reads().contains(m3));
-        assertTrue(m1.reads().contains(m4));
-        assertTrue(m1.reads().contains(base));
+        assertTrue(a.reads().size() == 4);
+        assertTrue(a.reads().contains(b));
+        assertTrue(a.reads().contains(c));
+        assertTrue(a.reads().contains(d));
+        assertTrue(a.reads().contains(base));
 
-        assertTrue(m2.reads().size() == 3);
-        assertTrue(m2.reads().contains(m3));
-        assertTrue(m2.reads().contains(m4));
-        assertTrue(m2.reads().contains(base));
+        assertTrue(b.reads().size() == 3);
+        assertTrue(b.reads().contains(c));
+        assertTrue(b.reads().contains(d));
+        assertTrue(b.reads().contains(base));
 
-        assertTrue(reads(cf, "m2", "m3"));
-        assertTrue(reads(cf, "m2", "m4"));
-        assertTrue(reads(cf, "m2", "java.base"));
+        assertTrue(reads(cf, "b", "c"));
+        assertTrue(reads(cf, "b", "d"));
+        assertTrue(reads(cf, "b", "java.base"));
 
-        assertTrue(m3.reads().contains(m1));
-        assertTrue(m3.reads().contains(m2));
-        assertTrue(m3.reads().contains(m4));
-        testReadAllBootModules(cf, "m3");   // m3 reads all modules in boot layer
+        assertTrue(c.reads().contains(a));
+        assertTrue(c.reads().contains(b));
+        assertTrue(c.reads().contains(d));
+        testReadAllBootModules(cf, "c");   // c reads all modules in boot layer
 
-        assertTrue(m4.reads().contains(m1));
-        assertTrue(m4.reads().contains(m2));
-        assertTrue(m4.reads().contains(m3));
-        testReadAllBootModules(cf, "m4");    // m4 reads all modules in boot layer
+        assertTrue(d.reads().contains(a));
+        assertTrue(d.reads().contains(b));
+        assertTrue(d.reads().contains(c));
+        testReadAllBootModules(cf, "d");    // d reads all modules in boot layer
     }
 
 
@@ -604,23 +613,23 @@
      */
     public void testInLayer() throws IOException {
         ModuleDescriptor descriptor
-            =  new ModuleDescriptor.Builder("m1")
-                .requires("m2")
-                .requires("m3")
+            = ModuleDescriptor.module("a")
+                .requires("b")
+                .requires("c")
                 .build();
 
-        // m2 and m3 are simple JAR files
+        // b and c are simple JAR files
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m2.jar"), "p/T.class");
-        createDummyJarFile(dir.resolve("m3.jar"), "q/T2.class");
+        createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
+        createDummyJarFile(dir.resolve("c.jar"), "q/T2.class");
 
-        // module finder locates m1 and the modules in the directory
+        // module finder locates a and the modules in the directory
         ModuleFinder finder
             = ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
                 ModuleFinder.of(dir));
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1");
+        Configuration cf = resolve(parent, finder, "a");
         assertTrue(cf.modules().size() == 3);
 
         // each module gets its own loader
@@ -629,15 +638,15 @@
         // an unnamed module
         Module unnamed = (new ClassLoader() { }).getUnnamedModule();
 
-        Module m2 = layer.findModule("m2").get();
-        assertTrue(m2.isNamed());
-        assertTrue(m2.canRead(unnamed));
-        testsReadsAll(m2, layer);
+        Module b = layer.findModule("b").get();
+        assertTrue(b.isNamed());
+        assertTrue(b.canRead(unnamed));
+        testsReadsAll(b, layer);
 
-        Module m3 = layer.findModule("m3").get();
-        assertTrue(m3.isNamed());
-        assertTrue(m2.canRead(unnamed));
-        testsReadsAll(m3, layer);
+        Module c = layer.findModule("c").get();
+        assertTrue(c.isNamed());
+        assertTrue(b.canRead(unnamed));
+        testsReadsAll(c, layer);
     }
 
 
@@ -646,19 +655,19 @@
      */
     public void testMisc() throws IOException {
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        Path m1_jar = createDummyJarFile(dir.resolve("m1.jar"), "p/T.class");
+        Path m_jar = createDummyJarFile(dir.resolve("m.jar"), "p/T.class");
 
-        ModuleFinder finder = ModuleFinder.of(m1_jar);
+        ModuleFinder finder = ModuleFinder.of(m_jar);
 
-        assertTrue(finder.find("m1").isPresent());
-        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
+        assertTrue(finder.find("m").isPresent());
+        ModuleDescriptor m = finder.find("m").get().descriptor();
 
         // test miscellaneous methods
-        assertTrue(m1.isAutomatic());
-        assertFalse(m1.isSynthetic());
-        assertFalse(m1.osName().isPresent());
-        assertFalse(m1.osArch().isPresent());
-        assertFalse(m1.osVersion().isPresent());
+        assertTrue(m.isAutomatic());
+        assertFalse(m.isSynthetic());
+        assertFalse(m.osName().isPresent());
+        assertFalse(m.osArch().isPresent());
+        assertFalse(m.osVersion().isPresent());
     }
 
 
@@ -703,17 +712,15 @@
      * and its parent Layers.
      */
     static void testsReadsAll(Module m, Layer layer) {
-        while (layer != Layer.empty()) {
+        // check that m reads all modules in the layer
+        layer.configuration().modules().stream()
+            .map(ResolvedModule::name)
+            .map(layer::findModule)
+            .map(Optional::get)
+            .forEach(other -> assertTrue(m.canRead(other)));
 
-            // check that m reads all module in the layer
-            layer.configuration().modules().stream()
-                .map(ResolvedModule::name)
-                .map(layer::findModule)
-                .map(Optional::get)
-                .forEach(m2 -> assertTrue(m.canRead(m2)));
-
-            layer = layer.parent().get();
-        }
+        // also check parent layers
+        layer.parents().forEach(l -> testsReadsAll(m, l));
     }
 
     /**
@@ -721,11 +728,11 @@
      * that reads module mn2.
      */
     static boolean reads(Configuration cf, String mn1, String mn2) {
-        Optional<ResolvedModule> om1 = cf.findModule(mn1);
-        if (!om1.isPresent())
+        Optional<ResolvedModule> om = cf.findModule(mn1);
+        if (!om.isPresent())
             return false;
 
-        return om1.get().reads().stream()
+        return om.get().reads().stream()
                 .map(ResolvedModule::name)
                 .anyMatch(mn2::equals);
     }
@@ -757,7 +764,7 @@
      * in the resulting JAR file.
      */
     static Path createDummyJarFile(Path jarfile, String... entries)
-        throws IOException
+            throws IOException
     {
         return createDummyJarFile(jarfile, null, entries);
     }
--- a/jdk/test/java/lang/module/ConfigurationTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/module/ConfigurationTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -31,11 +31,13 @@
 
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ResolutionException;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 
@@ -53,17 +55,17 @@
      */
     public void testBasic() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m3")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .build();
 
         ModuleFinder finder
@@ -77,7 +79,8 @@
         assertTrue(cf.findModule("m2").isPresent());
         assertTrue(cf.findModule("m3").isPresent());
 
-        assertTrue(cf.parent().get() == Configuration.empty());
+        assertTrue(cf.parents().size() == 1);
+        assertTrue(cf.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf.findModule("m1").get();
         ResolvedModule m2 = cf.findModule("m2").get();
@@ -102,23 +105,23 @@
 
 
     /**
-     * Basic test of "requires public":
-     *     m1 requires m2, m2 requires public m3
+     * Basic test of "requires transitive":
+     *     m1 requires m2, m2 requires transitive m3
      */
-    public void testRequiresPublic1() {
-        // m1 requires m2, m2 requires public m3
+    public void testRequiresTransitive1() {
+        // m1 requires m2, m2 requires transitive m3
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m3")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m3")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .build();
 
         ModuleFinder finder
@@ -132,7 +135,8 @@
         assertTrue(cf.findModule("m2").isPresent());
         assertTrue(cf.findModule("m3").isPresent());
 
-        assertTrue(cf.parent().get() == Configuration.empty());
+        assertTrue(cf.parents().size() == 1);
+        assertTrue(cf.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf.findModule("m1").get();
         ResolvedModule m2 = cf.findModule("m2").get();
@@ -153,23 +157,23 @@
 
 
     /**
-     * Basic test of "requires public" with configurations.
+     * Basic test of "requires transitive" with configurations.
      *
      * The test consists of three configurations:
-     * - Configuration cf1: m1, m2 requires public m1
+     * - Configuration cf1: m1, m2 requires transitive m1
      * - Configuration cf2: m3 requires m2
      */
-    public void testRequiresPublic2() {
-
-        // cf1: m1 and m2, m2 requires public m1
+    public void testRequiresTransitive2() {
+
+        // cf1: m1 and m2, m2 requires transitive m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -179,7 +183,8 @@
         assertTrue(cf1.modules().size() == 2);
         assertTrue(cf1.findModule("m1").isPresent());
         assertTrue(cf1.findModule("m2").isPresent());
-        assertTrue(cf1.parent().get() == Configuration.empty());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf1.findModule("m1").get();
         ResolvedModule m2 = cf1.findModule("m2").get();
@@ -192,7 +197,7 @@
         // cf2: m3, m3 requires m2
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -204,7 +209,8 @@
         assertTrue(cf2.findModule("m1").isPresent());  // in parent
         assertTrue(cf2.findModule("m2").isPresent());  // in parent
         assertTrue(cf2.findModule("m3").isPresent());
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         ResolvedModule m3 = cf2.findModule("m3").get();
         assertTrue(m3.configuration() == cf2);
@@ -215,18 +221,18 @@
 
 
     /**
-     * Basic test of "requires public" with configurations.
+     * Basic test of "requires transitive" with configurations.
      *
      * The test consists of three configurations:
      * - Configuration cf1: m1
-     * - Configuration cf2: m2 requires public m1, m3 requires m2
+     * - Configuration cf2: m2 requires transitive m1, m3 requires m2
      */
-    public void testRequiresPublic3() {
+    public void testRequiresTransitive3() {
 
         // cf1: m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -235,21 +241,22 @@
 
         assertTrue(cf1.modules().size() == 1);
         assertTrue(cf1.findModule("m1").isPresent());
-        assertTrue(cf1.parent().get() == Configuration.empty());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf1.findModule("m1").get();
         assertTrue(m1.reads().size() == 0);
 
 
-        // cf2: m2, m3: m2 requires public m1, m3 requires m2
+        // cf2: m2, m3: m2 requires transitive m1, m3 requires m2
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -261,7 +268,8 @@
         assertTrue(cf2.findModule("m1").isPresent());   // in parent
         assertTrue(cf2.findModule("m2").isPresent());
         assertTrue(cf2.findModule("m3").isPresent());
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         ResolvedModule m2 = cf2.findModule("m2").get();
         ResolvedModule m3 = cf2.findModule("m3").get();
@@ -278,19 +286,19 @@
 
 
     /**
-     * Basic test of "requires public" with configurations.
+     * Basic test of "requires transitive" with configurations.
      *
      * The test consists of three configurations:
      * - Configuration cf1: m1
-     * - Configuration cf2: m2 requires public m1
+     * - Configuration cf2: m2 requires transitive m1
      * - Configuraiton cf3: m3 requires m2
      */
-    public void testRequiresPublic4() {
+    public void testRequiresTransitive4() {
 
         // cf1: m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -299,17 +307,18 @@
 
         assertTrue(cf1.modules().size() == 1);
         assertTrue(cf1.findModule("m1").isPresent());
-        assertTrue(cf1.parent().get() == Configuration.empty());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf1.findModule("m1").get();
         assertTrue(m1.reads().size() == 0);
 
 
-        // cf2: m2 requires public m1
+        // cf2: m2 requires transitive m1
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
@@ -319,7 +328,8 @@
         assertTrue(cf2.modules().size() == 1);
         assertTrue(cf2.findModule("m1").isPresent());  // in parent
         assertTrue(cf2.findModule("m2").isPresent());
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         ResolvedModule m2 = cf2.findModule("m2").get();
 
@@ -331,7 +341,7 @@
         // cf3: m3 requires m2
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -343,7 +353,8 @@
         assertTrue(cf3.findModule("m1").isPresent());  // in parent
         assertTrue(cf3.findModule("m2").isPresent());  // in parent
         assertTrue(cf3.findModule("m3").isPresent());
-        assertTrue(cf3.parent().get() == cf2);
+        assertTrue(cf3.parents().size() == 1);
+        assertTrue(cf3.parents().get(0) == cf2);
 
         ResolvedModule m3 = cf3.findModule("m3").get();
 
@@ -355,23 +366,23 @@
 
 
     /**
-     * Basic test of "requires public" with configurations.
+     * Basic test of "requires transitive" with configurations.
      *
      * The test consists of two configurations:
-     * - Configuration cf1: m1, m2 requires public m1
-     * - Configuration cf2: m3 requires public m2, m4 requires m3
+     * - Configuration cf1: m1, m2 requires transitive m1
+     * - Configuration cf2: m3 requires transitive m2, m4 requires m3
      */
-    public void testRequiresPublic5() {
-
-        // cf1: m1, m2 requires public m1
+    public void testRequiresTransitive5() {
+
+        // cf1: m1, m2 requires transitive m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -381,7 +392,8 @@
         assertTrue(cf1.modules().size() == 2);
         assertTrue(cf1.findModule("m1").isPresent());
         assertTrue(cf1.findModule("m2").isPresent());
-        assertTrue(cf1.parent().get() == Configuration.empty());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf1.findModule("m1").get();
         ResolvedModule m2 = cf1.findModule("m2").get();
@@ -394,15 +406,15 @@
         assertTrue(m2.reads().contains(m1));
 
 
-        // cf2: m3 requires public m2, m4 requires m3
+        // cf2: m3 requires transitive m2, m4 requires m3
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .requires(Modifier.PUBLIC, "m2")
+            = ModuleDescriptor.module("m3")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2")
                 .build();
 
         ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4")
+            = ModuleDescriptor.module("m4")
                 .requires("m3")
                 .build();
 
@@ -416,7 +428,8 @@
         assertTrue(cf2.findModule("m2").isPresent());   // in parent
         assertTrue(cf2.findModule("m3").isPresent());
         assertTrue(cf2.findModule("m4").isPresent());
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         ResolvedModule m3 = cf2.findModule("m3").get();
         ResolvedModule m4 = cf2.findModule("m4").get();
@@ -435,6 +448,362 @@
 
 
     /**
+     * Basic test of "requires transitive" with configurations.
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1, m2 requires transitive m1
+     * - Configuration cf2: m1, m3 requires transitive m1
+     * - Configuration cf3(cf1,cf2): m4 requires m2, m3
+     */
+    public void testRequiresTransitive6() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+                .build();
+
+        ModuleDescriptor descriptor4
+            = ModuleDescriptor.module("m4")
+                .requires("m2")
+                .requires("m3")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+        Configuration cf1 = resolveRequires(finder1, "m2");
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.findModule("m2").isPresent());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
+        Configuration cf2 = resolveRequires(finder2, "m3");
+        assertTrue(cf2.modules().size() == 2);
+        assertTrue(cf2.findModule("m3").isPresent());
+        assertTrue(cf2.findModule("m1").isPresent());
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == Configuration.empty());
+
+        ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4);
+        Configuration cf3 = Configuration.resolveRequires(finder3,
+                List.of(cf1, cf2),
+                ModuleFinder.of(),
+                Set.of("m4"));
+        assertTrue(cf3.modules().size() == 1);
+        assertTrue(cf3.findModule("m4").isPresent());
+
+        ResolvedModule m1_l = cf1.findModule("m1").get();
+        ResolvedModule m1_r = cf2.findModule("m1").get();
+        ResolvedModule m2 = cf1.findModule("m2").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+        ResolvedModule m4 = cf3.findModule("m4").get();
+        assertTrue(m4.configuration() == cf3);
+
+        assertTrue(m4.reads().size() == 4);
+        assertTrue(m4.reads().contains(m1_l));
+        assertTrue(m4.reads().contains(m1_r));
+        assertTrue(m4.reads().contains(m2));
+        assertTrue(m4.reads().contains(m3));
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     m1 requires static m2
+     *     m2 is not observable
+     *     resolve m1
+     */
+    public void testRequiresStatic1() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 1);
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        assertTrue(m1.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     m1 requires static m2
+     *     m2
+     *     resolve m1
+     */
+    public void testRequiresStatic2() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 1);
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        assertTrue(m1.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     m1 requires static m2
+     *     m2
+     *     resolve m1, m2
+     */
+    public void testRequiresStatic3() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = resolveRequires(finder, "m1", "m2");
+
+        assertTrue(cf.modules().size() == 2);
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+
+        assertTrue(m1.reads().size() == 1);
+        assertTrue(m1.reads().contains(m2));
+
+        assertTrue(m2.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     m1 requires m2, m3
+     *     m2 requires static m2
+     *     m3
+     */
+    public void testRequiresStatic4() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .requires("m2")
+                .requires("m3")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.STATIC), "m3")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .build();
+
+        ModuleFinder finder
+                = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 3);
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+
+        assertTrue(m1.reads().size() == 2);
+        assertTrue(m1.reads().contains(m2));
+        assertTrue(m1.reads().contains(m3));
+
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m3));
+
+        assertTrue(m3.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     * The test consists of three configurations:
+     * - Configuration cf1: m1, m2
+     * - Configuration cf2: m3 requires m1, requires static m2
+     */
+    public void testRequiresStatic5() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m1", "m2");
+
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.findModule("m2").isPresent());
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m3").isPresent());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        ResolvedModule m2 = cf1.findModule("m2").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+
+        assertTrue(m3.reads().size() == 2);
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     * The test consists of three configurations:
+     * - Configuration cf1: m1
+     * - Configuration cf2: m3 requires m1, requires static m2
+     */
+    public void testRequiresStatic6() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder1, "m1");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m3").isPresent());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+
+        assertTrue(m3.reads().size() == 1);
+        assertTrue(m3.reads().contains(m1));
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     (m1 not observable)
+     *     m2 requires transitive static m1
+     *     m3 requires m2
+     */
+    public void testRequiresStatic7() {
+        ModuleDescriptor descriptor1 = null;  // not observable
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE,
+                                Requires.Modifier.STATIC),
+                         "m1")
+                .build();
+
+        ModuleDescriptor descriptor3
+                = ModuleDescriptor.module("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor2, descriptor3);
+
+        Configuration cf = resolveRequires(finder, "m3");
+
+        assertTrue(cf.modules().size() == 2);
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+        assertTrue(m2.reads().isEmpty());
+        assertTrue(m3.reads().size() == 1);
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     * - Configuration cf1: m2 requires transitive static m1
+     * - Configuration cf2: m3 requires m2
+     */
+    public void testRequiresStatic8() {
+        ModuleDescriptor descriptor1 = null;  // not observable
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE,
+                                Requires.Modifier.STATIC),
+                        "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m2");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m2").isPresent());
+        ResolvedModule m2 = cf1.findModule("m2").get();
+        assertTrue(m2.reads().isEmpty());
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m3").isPresent());
+        ResolvedModule m3 = cf2.findModule("m3").get();
+        assertTrue(m3.reads().size() == 1);
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
      * Basic test of binding services
      *     m1 uses p.S
      *     m2 provides p.S
@@ -442,15 +811,15 @@
     public void testServiceBinding1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -461,7 +830,8 @@
         assertTrue(cf.modules().size() == 2);
         assertTrue(cf.findModule("m1").isPresent());
         assertTrue(cf.findModule("m2").isPresent());
-        assertTrue(cf.parent().get() == Configuration.empty());
+        assertTrue(cf.parents().size() == 1);
+        assertTrue(cf.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf.findModule("m1").get();
         ResolvedModule m2 = cf.findModule("m2").get();
@@ -484,23 +854,23 @@
     public void testServiceBinding2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .uses("p.S2")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S1", "q.Service1Impl")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S2", "q.Service2Impl")
                 .build();
 
@@ -513,7 +883,8 @@
         assertTrue(cf.findModule("m1").isPresent());
         assertTrue(cf.findModule("m2").isPresent());
         assertTrue(cf.findModule("m3").isPresent());
-        assertTrue(cf.parent().get() == Configuration.empty());
+        assertTrue(cf.parents().size() == 1);
+        assertTrue(cf.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf.findModule("m1").get();
         ResolvedModule m2 = cf.findModule("m2").get();
@@ -542,7 +913,7 @@
     public void testServiceBindingWithConfigurations1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
@@ -555,9 +926,9 @@
         assertTrue(cf1.findModule("m1").isPresent());
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -565,7 +936,9 @@
 
         Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
+
         assertTrue(cf2.modules().size() == 1);
         assertTrue(cf2.findModule("m2").isPresent());
 
@@ -589,17 +962,17 @@
     public void testServiceBindingWithConfigurations2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
-                .conceals("p1")
+                .contains("p1")
                 .provides("p.S", "p1.ServiceImpl")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("p2")
+                .contains("p2")
                 .provides("p.S", "p2.ServiceImpl")
                 .build();
 
@@ -613,16 +986,16 @@
 
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m1")
-                .conceals("p3")
+                .contains("p3")
                 .provides("p.S", "p3.ServiceImpl")
                 .build();
 
         ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4")
+            = ModuleDescriptor.module("m4")
                 .requires("m1")
-                .conceals("p4")
+                .contains("p4")
                 .provides("p.S", "p4.ServiceImpl")
                 .build();
 
@@ -630,7 +1003,9 @@
 
         Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
+
         assertTrue(cf2.modules().size() == 2);
         assertTrue(cf2.findModule("m3").isPresent());
         assertTrue(cf2.findModule("m4").isPresent());
@@ -663,15 +1038,15 @@
     public void testServiceBindingWithConfigurations3() {
 
         ModuleDescriptor service
-            = new ModuleDescriptor.Builder("s")
+            = ModuleDescriptor.module("s")
                 .exports("p")
                 .build();
 
         ModuleDescriptor provider_v1
-            = new ModuleDescriptor.Builder("p")
+            = ModuleDescriptor.module("p")
                 .version("1.0")
                 .requires("s")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -689,16 +1064,16 @@
 
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("s")
                 .uses("p.S")
                 .build();
 
         ModuleDescriptor provider_v2
-            = new ModuleDescriptor.Builder("p")
+            = ModuleDescriptor.module("p")
                 .version("2.0")
                 .requires("s")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -709,7 +1084,8 @@
 
         Configuration cf2 = resolveRequiresAndUses(cf1, finder2, "m1");
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
         assertTrue(cf2.modules().size() == 2);
 
         // p should be found in cf2
@@ -723,7 +1099,8 @@
 
         cf2 = resolveRequiresAndUses(cf1, ModuleFinder.of(), finder2, "m1");
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
         assertTrue(cf2.modules().size() == 1);
 
         // p should be found in cf1
@@ -741,17 +1118,17 @@
     public void testWithTwoFinders1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
 
         ModuleDescriptor descriptor2_v1
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .version("1.0")
                 .build();
 
         ModuleDescriptor descriptor2_v2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .version("2.0")
                 .build();
 
@@ -781,22 +1158,22 @@
     public void testWithTwoFinders2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
 
         ModuleDescriptor descriptor2_v1
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
         ModuleDescriptor descriptor2_v2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -824,7 +1201,7 @@
     public void testResolvedInParent1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
@@ -847,7 +1224,7 @@
     public void testResolvedInParent2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -859,7 +1236,7 @@
 
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .build();
 
@@ -880,12 +1257,221 @@
 
 
     /**
-     * Basic test of using the beforeFinder to override a module in the parent
+     * Basic test of resolving a module that depends on modules in two parent
+     * configurations.
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1
+     * - Configuration cf2: m2
+     * - Configuration cf3(cf1,cf2): m3 requires m1, m2
+     */
+    public void testResolvedInMultipleParents1() {
+
+        // Configuration cf1: m1
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build();
+        Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1");
+        assertEquals(cf1.parents(), List.of(Configuration.empty()));
+        assertTrue(cf1.findModule("m1").isPresent());
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        assertTrue(m1.configuration() == cf1);
+
+        // Configuration cf2: m2
+        ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build();
+        Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2");
+        assertEquals(cf2.parents(), List.of(Configuration.empty()));
+        assertTrue(cf2.findModule("m2").isPresent());
+        ResolvedModule m2 = cf2.findModule("m2").get();
+        assertTrue(m2.configuration() == cf2);
+
+        // Configuration cf3(cf1,cf2): m3 requires m1 and m2
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m1")
+                .requires("m2")
+                .build();
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor3);
+        Configuration cf3 = Configuration.resolveRequires(
+                finder,
+                List.of(cf1, cf2),  // parents
+                ModuleFinder.of(),
+                Set.of("m3"));
+        assertEquals(cf3.parents(), List.of(cf1, cf2));
+        assertTrue(cf3.findModule("m3").isPresent());
+        ResolvedModule m3 = cf3.findModule("m3").get();
+        assertTrue(m3.configuration() == cf3);
+
+        // check readability
+        assertTrue(m1.reads().isEmpty());
+        assertTrue(m2.reads().isEmpty());
+        assertEquals(m3.reads(), Set.of(m1, m2));
+    }
+
+
+    /**
+     * Basic test of resolving a module that depends on modules in three parent
+     * configurations arranged in a diamond (two direct parents).
+     *
+     * The test consists of four configurations:
+     * - Configuration cf1: m1
+     * - Configuration cf2(cf1): m2 requires m1
+     * - Configuration cf3(cf3): m3 requires m1
+     * - Configuration cf4(cf2,cf3): m4 requires m1,m2,m3
+     */
+    public void testResolvedInMultipleParents2() {
+        // Configuration cf1: m1
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build();
+        Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1");
+        assertEquals(cf1.parents(), List.of(Configuration.empty()));
+        assertTrue(cf1.findModule("m1").isPresent());
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        assertTrue(m1.configuration() == cf1);
+
+        // Configuration cf2(cf1): m2 requires m1
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires("m1")
+                .build();
+        Configuration cf2 = Configuration.resolveRequires(
+                ModuleUtils.finderOf(descriptor2),
+                List.of(cf1),  // parents
+                ModuleFinder.of(),
+                Set.of("m2"));
+        assertEquals(cf2.parents(), List.of(cf1));
+        assertTrue(cf2.findModule("m2").isPresent());
+        ResolvedModule m2 = cf2.findModule("m2").get();
+        assertTrue(m2.configuration() == cf2);
+
+        // Configuration cf3(cf1): m3 requires m1
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m1")
+                .build();
+        Configuration cf3 = Configuration.resolveRequires(
+                ModuleUtils.finderOf(descriptor3),
+                List.of(cf1),  // parents
+                ModuleFinder.of(),
+                Set.of("m3"));
+        assertEquals(cf3.parents(), List.of(cf1));
+        assertTrue(cf3.findModule("m3").isPresent());
+        ResolvedModule m3 = cf3.findModule("m3").get();
+        assertTrue(m3.configuration() == cf3);
+
+        // Configuration cf4(cf2,cf3): m4 requires m1,m2,m3
+        ModuleDescriptor descriptor4
+            = ModuleDescriptor.module("m4")
+                .requires("m1")
+                .requires("m2")
+                .requires("m3")
+                .build();
+        Configuration cf4 = Configuration.resolveRequires(
+                ModuleUtils.finderOf(descriptor4),
+                List.of(cf2, cf3),  // parents
+                ModuleFinder.of(),
+                Set.of("m4"));
+        assertEquals(cf4.parents(), List.of(cf2, cf3));
+        assertTrue(cf4.findModule("m4").isPresent());
+        ResolvedModule m4 = cf4.findModule("m4").get();
+        assertTrue(m4.configuration() == cf4);
+
+        // check readability
+        assertTrue(m1.reads().isEmpty());
+        assertEquals(m2.reads(), Set.of(m1));
+        assertEquals(m3.reads(), Set.of(m1));
+        assertEquals(m4.reads(), Set.of(m1, m2, m3));
+    }
+
+
+    /**
+     * Basic test of resolving a module that depends on modules in three parent
+     * configurations arranged in a diamond (two direct parents).
+     *
+     * The test consists of four configurations:
+     * - Configuration cf1: m1@1
+     * - Configuration cf2: m1@2, m2@2
+     * - Configuration cf3: m1@3, m2@3, m3@3
+     * - Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3
+     */
+    public void testResolvedInMultipleParents3() {
+        ModuleDescriptor descriptor1, descriptor2, descriptor3;
+
+        // Configuration cf1: m1@1
+        descriptor1 = ModuleDescriptor.module("m1").version("1").build();
+        Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1");
+        assertEquals(cf1.parents(), List.of(Configuration.empty()));
+
+        // Configuration cf2: m1@2, m2@2
+        descriptor1 = ModuleDescriptor.module("m1").version("2").build();
+        descriptor2 = ModuleDescriptor.module("m2").version("2").build();
+        Configuration cf2 = resolveRequires(
+                ModuleUtils.finderOf(descriptor1, descriptor2),
+                "m1", "m2");
+        assertEquals(cf2.parents(), List.of(Configuration.empty()));
+
+        // Configuration cf3: m1@3, m2@3, m3@3
+        descriptor1 = ModuleDescriptor.module("m1").version("3").build();
+        descriptor2 = ModuleDescriptor.module("m2").version("3").build();
+        descriptor3 = ModuleDescriptor.module("m3").version("3").build();
+        Configuration cf3 = resolveRequires(
+                ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3),
+                "m1", "m2", "m3");
+        assertEquals(cf3.parents(), List.of(Configuration.empty()));
+
+        // Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3
+        ModuleDescriptor descriptor4
+                = ModuleDescriptor.module("m4")
+                .requires("m1")
+                .requires("m2")
+                .requires("m3")
+                .build();
+        Configuration cf4 = Configuration.resolveRequires(
+                ModuleUtils.finderOf(descriptor4),
+                List.of(cf1, cf2, cf3),  // parents
+                ModuleFinder.of(),
+                Set.of("m4"));
+        assertEquals(cf4.parents(), List.of(cf1, cf2, cf3));
+
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf2.findModule("m1").isPresent());
+        assertTrue(cf2.findModule("m2").isPresent());
+        assertTrue(cf3.findModule("m1").isPresent());
+        assertTrue(cf3.findModule("m2").isPresent());
+        assertTrue(cf3.findModule("m3").isPresent());
+        assertTrue(cf4.findModule("m4").isPresent());
+
+        ResolvedModule m1_1 = cf1.findModule("m1").get();
+        ResolvedModule m1_2 = cf2.findModule("m1").get();
+        ResolvedModule m2_2 = cf2.findModule("m2").get();
+        ResolvedModule m1_3 = cf3.findModule("m1").get();
+        ResolvedModule m2_3 = cf3.findModule("m2").get();
+        ResolvedModule m3_3 = cf3.findModule("m3").get();
+        ResolvedModule m4   = cf4.findModule("m4").get();
+
+        assertTrue(m1_1.configuration() == cf1);
+        assertTrue(m1_2.configuration() == cf2);
+        assertTrue(m2_2.configuration() == cf2);
+        assertTrue(m1_3.configuration() == cf3);
+        assertTrue(m2_3.configuration() == cf3);
+        assertTrue(m3_3.configuration() == cf3);
+        assertTrue(m4.configuration() == cf4);
+
+        // check readability
+        assertTrue(m1_1.reads().isEmpty());
+        assertTrue(m1_2.reads().isEmpty());
+        assertTrue(m2_2.reads().isEmpty());
+        assertTrue(m1_3.reads().isEmpty());
+        assertTrue(m2_3.reads().isEmpty());
+        assertTrue(m3_3.reads().isEmpty());
+        assertEquals(m4.reads(), Set.of(m1_1, m2_2, m3_3));
+    }
+
+
+    /**
+     * Basic test of using the beforeFinder to override a module in a parent
      * configuration.
      */
     public void testOverriding1() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
@@ -899,6 +1485,39 @@
         assertTrue(cf2.findModule("m1").isPresent());
     }
 
+    /**
+     * Basic test of using the beforeFinder to override a module in a parent
+     * configuration.
+     */
+    public void testOverriding2() {
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build();
+        Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1");
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+
+        ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build();
+        Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2");
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m2").isPresent());
+
+        ModuleDescriptor descriptor3 = ModuleDescriptor.module("m3").build();
+        Configuration cf3 = resolveRequires(ModuleUtils.finderOf(descriptor3), "m3");
+        assertTrue(cf3.modules().size() == 1);
+        assertTrue(cf3.findModule("m3").isPresent());
+
+        // override m2, m1 and m3 should be found in parent configurations
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor2);
+        Configuration cf4 = Configuration.resolveRequires(
+                finder,
+                List.of(cf1, cf2, cf3),
+                ModuleFinder.of(),
+                Set.of("m1", "m2", "m3"));
+        assertTrue(cf4.modules().size() == 1);
+        assertTrue(cf4.findModule("m2").isPresent());
+        ResolvedModule m2 = cf4.findModule("m2").get();
+        assertTrue(m2.configuration() == cf4);
+    }
+
 
     /**
      * Basic test of using the beforeFinder to override a module in the parent
@@ -906,18 +1525,18 @@
      * module in the parent is read.
      *
      * The test consists of two configurations:
-     * - Configuration cf1: m1, m2 requires public m1
+     * - Configuration cf1: m1, m2 requires transitive m1
      * - Configuration cf2: m1, m3 requires m2
      */
-    public void testOverriding2() {
+    public void testOverriding3() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -931,7 +1550,7 @@
         // cf2: m3 requires m2, m1
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -939,7 +1558,8 @@
 
         Configuration cf2 = resolveRequires(cf1, finder2, "m1", "m3");
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         assertTrue(cf2.modules().size() == 2);
         assertTrue(cf2.findModule("m1").isPresent());
@@ -977,7 +1597,7 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testDirectDependencyNotFound() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+            = ModuleDescriptor.module("m1").requires("m2").build();
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
         resolveRequires(finder, "m1");
     }
@@ -989,9 +1609,9 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testTransitiveDependencyNotFound() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+            = ModuleDescriptor.module("m1").requires("m2").build();
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2").requires("m3").build();
+            = ModuleDescriptor.module("m2").requires("m3").build();
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
         resolveRequires(finder, "m1");
     }
@@ -1006,16 +1626,16 @@
         // service provider dependency (on m3) not found
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .requires("m3")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -1032,11 +1652,11 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testSimpleCycle() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+            = ModuleDescriptor.module("m1").requires("m2").build();
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2").requires("m3").build();
+            = ModuleDescriptor.module("m2").requires("m3").build();
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3").requires("m1").build();
+            = ModuleDescriptor.module("m3").requires("m1").build();
         ModuleFinder finder
             = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
         resolveRequires(finder, "m1");
@@ -1049,19 +1669,19 @@
     public void testCycleInProvider() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .requires("m3")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -1080,19 +1700,19 @@
     public void testPackageSuppliedByTwoOthers() {
 
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
                 .requires("m3")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
+            =  ModuleDescriptor.module("m2")
                 .exports("p")
                 .build();
 
         ModuleDescriptor descriptor3
-            =  new ModuleDescriptor.Builder("m3")
-                .exports("p", "m1")
+            =  ModuleDescriptor.module("m3")
+                .exports("p", Set.of("m1"))
                 .build();
 
         ModuleFinder finder
@@ -1104,45 +1724,44 @@
 
 
     /**
-     * Test the scenario where a module has a concealed package p and reads
+     * Test the scenario where a module contains a package p and reads
      * a module that exports package p.
      */
     @Test(expectedExceptions = { ResolutionException.class })
     public void testPackageSuppliedBySelfAndOther() {
 
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
-                .conceals("p")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
+            =  ModuleDescriptor.module("m2")
                 .exports("p")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
 
-        //  m1 contains package p, module m2 exports package p to m1
+        // m1 contains package p, module m2 exports package p to m1
         resolveRequires(finder, "m1");
     }
 
 
     /**
-     * Test the scenario where a module has a concealed package p and reads
-     * a module that also has a concealed package p.
+     * Test the scenario where a module contains a package p and reads
+     * a module that also contains a package p.
      */
-    public void testPackagePrivateToSelfAndOther() {
-
+    public void testContainsPackageInSelfAndOther() {
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
-                .conceals("p")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .conceals("p")
+            =  ModuleDescriptor.module("m2")
+                .contains("p")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -1169,7 +1788,7 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testExportSamePackageAsBootLayer() {
         ModuleDescriptor descriptor
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("java.base")
                 .exports("java.lang")
                 .build();
@@ -1184,12 +1803,12 @@
 
 
     /**
-     * Test "uses p.S" where p is a concealed package in the same module.
+     * Test "uses p.S" where p is contained in the same module.
      */
-    public void testConcealedService1() {
+    public void testContainsService1() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
                 .uses("p.S")
                 .build();
 
@@ -1203,17 +1822,17 @@
 
 
     /**
-     * Test "uses p.S" where p is a concealed package in a different module.
+     * Test "uses p.S" where p is contained in a different module.
      */
     @Test(expectedExceptions = { ResolutionException.class })
-    public void testConcealedService2() {
+    public void testContainsService2() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .uses("p.S")
                 .build();
@@ -1226,13 +1845,13 @@
 
 
     /**
-     * Test "provides p.S" where p is a concealed package in the same module.
+     * Test "provides p.S" where p is contained in the same module.
      */
-    public void testConcealedService3() {
+    public void testContainsService3() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
-                .conceals("q")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
+                .contains("q")
                 .provides("p.S", "q.S1")
                 .build();
 
@@ -1246,19 +1865,19 @@
 
 
     /**
-     * Test "provides p.S" where p is a concealed package in a different module.
+     * Test "provides p.S" where p is contained in a different module.
      */
     @Test(expectedExceptions = { ResolutionException.class })
-    public void testConcealedService4() {
+    public void testContainsService4() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.S1")
                 .build();
 
@@ -1275,7 +1894,7 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testServiceTypePackageNotExported1() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .uses("p.S")
                 .build();
 
@@ -1292,8 +1911,8 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testServiceTypePackageNotExported2() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("q")
+            = ModuleDescriptor.module("m1")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -1310,13 +1929,13 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testProviderPackageNotLocal() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .exports("q")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .provides("p.S", "q.T")
                 .build();
@@ -1334,7 +1953,7 @@
     public void testEmptyConfiguration() {
         Configuration cf = Configuration.empty();
 
-        assertFalse(cf.parent().isPresent());
+        assertTrue(cf.parents().isEmpty());
 
         assertTrue(cf.modules().isEmpty());
         assertFalse(cf.findModule("java.base").isPresent());
@@ -1389,7 +2008,7 @@
     public void testPlatformMatch(String s1, String s2) {
 
         ModuleDescriptor.Builder builder
-            = new ModuleDescriptor.Builder("m1").requires("m2");
+            = ModuleDescriptor.module("m1").requires("m2");
 
         String[] s = s1.split("-");
         if (!s[0].equals("*"))
@@ -1401,7 +2020,7 @@
 
         ModuleDescriptor descriptor1 = builder.build();
 
-        builder = new ModuleDescriptor.Builder("m2");
+        builder = ModuleDescriptor.module("m2");
 
         s = s2.split("-");
         if (!s[0].equals("*"))
@@ -1433,6 +2052,21 @@
     }
 
 
+    // no parents
+
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testResolveRequiresWithNoParents() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration.resolveRequires(empty, List.of(), empty, Set.of());
+    }
+
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testResolveRequiresAndUsesWithNoParents() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration.resolveRequiresAndUses(empty, List.of(), empty, Set.of());
+    }
+
+
     // null handling
 
     // finder1, finder2, roots
@@ -1449,6 +2083,31 @@
     }
 
     @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull3() {
+        Configuration empty = Configuration.empty();
+        Configuration.resolveRequires(null, List.of(empty),  ModuleFinder.of(), Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull4() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration.resolveRequires(empty, null, empty, Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull5() {
+        Configuration cf = Layer.boot().configuration();
+        Configuration.resolveRequires(ModuleFinder.of(), List.of(cf), null, Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull6() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration cf = Layer.boot().configuration();
+        Configuration.resolveRequires(empty, List.of(cf), empty, null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
     public void testResolveRequiresAndUsesWithNull1() {
         resolveRequiresAndUses((ModuleFinder) null, ModuleFinder.of());
     }
@@ -1459,6 +2118,31 @@
     }
 
     @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull3() {
+        Configuration empty = Configuration.empty();
+        Configuration.resolveRequiresAndUses(null, List.of(empty), ModuleFinder.of(), Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull4() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration.resolveRequiresAndUses(empty, null, empty, Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull5() {
+        Configuration cf = Layer.boot().configuration();
+        Configuration.resolveRequiresAndUses(ModuleFinder.of(), List.of(cf), null, Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull6() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration cf = Layer.boot().configuration();
+        Configuration.resolveRequiresAndUses(empty, List.of(cf), empty, null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
     public void testFindModuleWithNull() {
         Configuration.empty().findModule(null);
     }
--- a/jdk/test/java/lang/module/ModuleDescriptorTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,28 +23,34 @@
 
 /**
  * @test
- * @modules java.base/jdk.internal.module
+ * @modules java.base/java.lang.module:open
+ *          java.base/jdk.internal.module
  * @run testng ModuleDescriptorTest
  * @summary Basic test for java.lang.module.ModuleDescriptor and its builder
  */
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.module.InvalidModuleDescriptorException;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Builder;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires.Modifier;
 import java.lang.module.ModuleDescriptor.Version;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Module;
 import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
 
@@ -72,7 +78,7 @@
     // requires
 
     private Requires requires(Set<Modifier> mods, String mn) {
-        return new Builder("m")
+        return ModuleDescriptor.module("m")
             .requires(mods, mn)
             .build()
             .requires()
@@ -80,19 +86,15 @@
             .next();
     }
 
-    public void testRequiresWithRequires() {
-        Requires r1 = requires(null, "foo");
-        ModuleDescriptor descriptor = new Builder("m").requires(r1).build();
-        Requires r2 = descriptor.requires().iterator().next();
-        assertEquals(r1, r2);
+    private Requires requires(String mn) {
+        return requires(Collections.emptySet(), mn);
     }
 
-    public void testRequiresWithNullModifiers() {
-        Requires r = requires(null, "foo");
-        assertEquals(r, r);
-        assertTrue(r.compareTo(r) == 0);
-        assertTrue(r.modifiers().isEmpty());
-        assertEquals(r.name(), "foo");
+    public void testRequiresWithRequires() {
+        Requires r1 = requires("foo");
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m").requires(r1).build();
+        Requires r2 = descriptor.requires().iterator().next();
+        assertEquals(r1, r2);
     }
 
     public void testRequiresWithNoModifiers() {
@@ -104,18 +106,18 @@
     }
 
     public void testRequiresWithOneModifier() {
-        Requires r = requires(EnumSet.of(PUBLIC), "foo");
+        Requires r = requires(EnumSet.of(TRANSITIVE), "foo");
         assertEquals(r, r);
         assertTrue(r.compareTo(r) == 0);
-        assertEquals(r.modifiers(), EnumSet.of(PUBLIC));
+        assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE));
         assertEquals(r.name(), "foo");
     }
 
     public void testRequiresWithTwoModifiers() {
-        Requires r = requires(EnumSet.of(PUBLIC, SYNTHETIC), "foo");
+        Requires r = requires(EnumSet.of(TRANSITIVE, SYNTHETIC), "foo");
         assertEquals(r, r);
         assertTrue(r.compareTo(r) == 0);
-        assertEquals(r.modifiers(), EnumSet.of(PUBLIC, SYNTHETIC));
+        assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, SYNTHETIC));
         assertEquals(r.name(), "foo");
     }
 
@@ -123,35 +125,35 @@
         Requires r = requires(EnumSet.allOf(Modifier.class), "foo");
         assertEquals(r, r);
         assertTrue(r.compareTo(r) == 0);
-        assertEquals(r.modifiers(), EnumSet.allOf(Modifier.class));
+        assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, STATIC, SYNTHETIC, MANDATED));
         assertEquals(r.name(), "foo");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
     public void testRequiresWithDuplicatesRequires() {
-        Requires r = requires(null, "foo");
-        new Builder("m").requires(r).requires(r);
+        Requires r = requires("foo");
+        ModuleDescriptor.module("m").requires(r).requires(r);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testRequiresSelfWithRequires() {
-        Requires r = requires(null, "foo");
-        new Builder("foo").requires(r);
+        Requires r = requires("foo");
+        ModuleDescriptor.module("foo").requires(r);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testRequiresSelfWithNoModifier() {
-        new Builder("m").requires("m");
+        ModuleDescriptor.module("m").requires("m");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testRequiresSelfWithOneModifier() {
-        new Builder("m").requires(PUBLIC, "m");
+        ModuleDescriptor.module("m").requires(Set.of(TRANSITIVE), "m");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testRequiresSelfWithAllModifiers() {
-        new Builder("m").requires(EnumSet.allOf(Modifier.class), "m");
+        ModuleDescriptor.module("m").requires(EnumSet.allOf(Modifier.class), "m");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
@@ -162,7 +164,7 @@
 
     @Test(expectedExceptions = NullPointerException.class)
     public void testRequiresWithNullRequires() {
-        new Builder("m").requires((Requires) null);
+        ModuleDescriptor.module("m").requires((Requires) null);
     }
 
     public void testRequiresCompare() {
@@ -174,9 +176,9 @@
     }
 
     public void testRequiresCompareWithDifferentModifiers() {
-        Requires r1 = requires(EnumSet.of(PUBLIC), "foo");
+        Requires r1 = requires(EnumSet.of(TRANSITIVE), "foo");
         Requires r2 = requires(EnumSet.of(SYNTHETIC), "foo");
-        int n = Integer.compare(1 << PUBLIC.ordinal(), 1 << SYNTHETIC.ordinal());
+        int n = Integer.compare(1 << TRANSITIVE.ordinal(), 1 << SYNTHETIC.ordinal());
         assertTrue(r1.compareTo(r2) == n);
         assertTrue(r2.compareTo(r1) == -n);
     }
@@ -188,6 +190,26 @@
         assertTrue(r2.compareTo(r1) == 0);
     }
 
+    public void testRequiresEqualsAndHashCode() {
+        Requires r1 = requires("foo");
+        Requires r2 = requires("foo");
+        assertEquals(r1, r2);
+        assertTrue(r1.hashCode() == r2.hashCode());
+
+        r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
+        r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
+        assertEquals(r1, r2);
+        assertTrue(r1.hashCode() == r2.hashCode());
+
+        r1 = requires("foo");
+        r2 = requires("bar");
+        assertNotEquals(r1, r2);
+
+        r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
+        r2 = requires(Set.of(), "foo");
+        assertNotEquals(r1, r2);
+    }
+
     public void testRequiresToString() {
         Requires r = requires(EnumSet.noneOf(Modifier.class), "foo");
         assertTrue(r.toString().contains("foo"));
@@ -196,9 +218,22 @@
 
     // exports
 
+    private Exports exports(Set<Exports.Modifier> mods, String pn) {
+        return ModuleDescriptor.module("foo")
+            .exports(mods, pn)
+            .build()
+            .exports()
+            .iterator()
+            .next();
+    }
+
     private Exports exports(String pn) {
-        return new Builder("foo")
-            .exports(pn)
+        return exports(Set.of(), pn);
+    }
+
+    private Exports exports(Set<Exports.Modifier> mods, String pn, String target) {
+        return ModuleDescriptor.module("foo")
+            .exports(mods, pn, Set.of(target))
             .build()
             .exports()
             .iterator()
@@ -206,17 +241,13 @@
     }
 
     private Exports exports(String pn, String target) {
-        return new Builder("foo")
-            .exports(pn, target)
-            .build()
-            .exports()
-            .iterator()
-            .next();
+        return exports(Set.of(), pn, target);
     }
 
+
     public void testExportsExports() {
         Exports e1 = exports("p");
-        ModuleDescriptor descriptor = new Builder("m").exports(e1).build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m").exports(e1).build();
         Exports e2 = descriptor.exports().iterator().next();
         assertEquals(e1, e2);
     }
@@ -224,6 +255,7 @@
     public void testExportsToAll() {
         Exports e = exports("p");
         assertEquals(e, e);
+        assertTrue(e.modifiers().isEmpty());
         assertEquals(e.source(), "p");
         assertFalse(e.isQualified());
         assertTrue(e.targets().isEmpty());
@@ -232,6 +264,7 @@
     public void testExportsToTarget() {
         Exports e = exports("p", "bar");
         assertEquals(e, e);
+        assertTrue(e.modifiers().isEmpty());
         assertEquals(e.source(), "p");
         assertTrue(e.isQualified());
         assertTrue(e.targets().size() == 1);
@@ -243,13 +276,14 @@
         targets.add("bar");
         targets.add("gus");
         Exports e
-            = new Builder("foo")
+            = ModuleDescriptor.module("foo")
                 .exports("p", targets)
                 .build()
                 .exports()
                 .iterator()
                 .next();
         assertEquals(e, e);
+        assertTrue(e.modifiers().isEmpty());
         assertEquals(e.source(), "p");
         assertTrue(e.isQualified());
         assertTrue(e.targets().size() == 2);
@@ -257,56 +291,94 @@
         assertTrue(e.targets().contains("gus"));
     }
 
+    public void testExportsToAllWithModifier() {
+        Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        assertEquals(e, e);
+        assertTrue(e.modifiers().size() == 1);
+        assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC));
+        assertEquals(e.source(), "p");
+        assertFalse(e.isQualified());
+        assertTrue(e.targets().isEmpty());
+    }
+
+    public void testExportsToTargetWithModifier() {
+        Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", "bar");
+        assertEquals(e, e);
+        assertTrue(e.modifiers().size() == 1);
+        assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC));
+        assertEquals(e.source(), "p");
+        assertTrue(e.isQualified());
+        assertTrue(e.targets().size() == 1);
+        assertTrue(e.targets().contains("bar"));
+    }
+
     @Test(expectedExceptions = IllegalStateException.class)
     public void testExportsWithDuplicate1() {
         Exports e = exports("p");
-        new Builder("foo").exports(e).exports(e);
+        ModuleDescriptor.module("foo").exports(e).exports(e);
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
     public void testExportsWithDuplicate2() {
-        new Builder("foo").exports("p").exports("p");
+        ModuleDescriptor.module("foo").exports("p").exports("p");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void testExportsWithConcealedPackage() {
-        new Builder("foo").conceals("p").exports("p");
+    public void testExportsOnContainedPackage() {
+        ModuleDescriptor.module("foo").contains("p").exports("p");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void testExportsToTargetWithConcealedPackage() {
-        new Builder("foo").conceals("p").exports("p", "bar");
+    public void testExportsToTargetOnContainedPackage() {
+        ModuleDescriptor.module("foo").contains("p").exports("p", Set.of("bar"));
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class )
     public void testExportsWithEmptySet() {
-        new Builder("foo").exports("p", Collections.emptySet());
+        ModuleDescriptor.module("foo").exports("p", Collections.emptySet());
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testExportsWithBadName(String pn, String ignore) {
-        new Builder("foo").exports(pn);
+        ModuleDescriptor.module("foo").exports(pn);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testExportsWithNullExports() {
-        new Builder("foo").exports((Exports)null);
-    }
-
-    @Test(expectedExceptions = IllegalArgumentException.class )
-    public void testExportsWithNullTarget() {
-        new Builder("foo").exports("p", (String) null);
+        ModuleDescriptor.module("foo").exports((Exports) null);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testExportsWithNullTargets() {
-        new Builder("foo").exports("p", (Set<String>) null);
+        ModuleDescriptor.module("foo").exports("p", (Set<String>) null);
+    }
+
+    public void testExportsEqualsAndHashCode() {
+        Exports e1, e2;
+
+        e1 = exports("p");
+        e2 = exports("p");
+        assertEquals(e1, e2);
+        assertTrue(e1.hashCode() == e2.hashCode());
+
+        e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        e2 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        assertEquals(e1, e2);
+        assertTrue(e1.hashCode() == e2.hashCode());
+
+        e1 = exports("p");
+        e2 = exports("q");
+        assertNotEquals(e1, e2);
+
+        e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        e2 = exports(Set.of(), "p");
+        assertNotEquals(e1, e2);
     }
 
     public void testExportsToString() {
-        String s = new Builder("foo")
-            .exports("p1", "bar")
+        String s = ModuleDescriptor.module("foo")
+            .exports("p1", Set.of("bar"))
             .build()
             .exports()
             .iterator()
@@ -317,11 +389,188 @@
     }
 
 
+    // opens
+
+    private Opens opens(Set<Opens.Modifier> mods, String pn) {
+        return ModuleDescriptor.module("foo")
+                .opens(mods, pn)
+                .build()
+                .opens()
+                .iterator()
+                .next();
+    }
+
+    private Opens opens(String pn) {
+        return opens(Set.of(), pn);
+    }
+
+    private Opens opens(Set<Opens.Modifier> mods, String pn, String target) {
+        return ModuleDescriptor.module("foo")
+                .opens(mods, pn, Set.of(target))
+                .build()
+                .opens()
+                .iterator()
+                .next();
+    }
+
+    private Opens opens(String pn, String target) {
+        return opens(Set.of(), pn, target);
+    }
+
+    public void testOpensOpens() {
+        Opens o1 = opens("p");
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m").opens(o1).build();
+        Opens o2 = descriptor.opens().iterator().next();
+        assertEquals(o1, o2);
+    }
+
+    public void testOpensToAll() {
+        Opens o = opens("p");
+        assertEquals(o, o);
+        assertTrue(o.modifiers().isEmpty());
+        assertEquals(o.source(), "p");
+        assertFalse(o.isQualified());
+        assertTrue(o.targets().isEmpty());
+    }
+
+
+    public void testOpensToTarget() {
+        Opens o = opens("p", "bar");
+        assertEquals(o, o);
+        assertTrue(o.modifiers().isEmpty());
+        assertEquals(o.source(), "p");
+        assertTrue(o.isQualified());
+        assertTrue(o.targets().size() == 1);
+        assertTrue(o.targets().contains("bar"));
+    }
+
+    public void testOpensToTargets() {
+        Set<String> targets = new HashSet<>();
+        targets.add("bar");
+        targets.add("gus");
+        Opens o = ModuleDescriptor.module("foo")
+                .opens("p", targets)
+                .build()
+                .opens()
+                .iterator()
+                .next();
+        assertEquals(o, o);
+        assertTrue(o.modifiers().isEmpty());
+        assertEquals(o.source(), "p");
+        assertTrue(o.isQualified());
+        assertTrue(o.targets().size() == 2);
+        assertTrue(o.targets().contains("bar"));
+        assertTrue(o.targets().contains("gus"));
+    }
+
+    /*
+
+    public void testOpensToAllWithModifier() {
+        Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        assertEquals(e, e);
+        assertTrue(e.modifiers().size() == 1);
+        assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC));
+        assertEquals(e.source(), "p");
+        assertFalse(e.isQualified());
+        assertTrue(e.targets().isEmpty());
+    }
+
+    public void testOpensToTargetWithModifier() {
+        Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", Set.of("bar"));
+        assertEquals(e, e);
+        assertTrue(e.modifiers().size() == 1);
+        assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC));
+        assertEquals(e.source(), "p");
+        assertTrue(e.isQualified());
+        assertTrue(e.targets().size() == 1);
+        assertTrue(e.targets().contains("bar"));
+    }
+
+
+    */
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensWithDuplicate1() {
+        Opens o = opens("p");
+        ModuleDescriptor.module("foo").opens(o).opens(o);
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensWithDuplicate2() {
+        ModuleDescriptor.module("foo").opens("p").opens("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensOnContainedPackage() {
+        ModuleDescriptor.module("foo").contains("p").opens("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensToTargetOnContainedPackage() {
+        ModuleDescriptor.module("foo").contains("p").opens("p", Set.of("bar"));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class )
+    public void testOpensWithEmptySet() {
+        ModuleDescriptor.module("foo").opens("p", Collections.emptySet());
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+            expectedExceptions = IllegalArgumentException.class )
+    public void testOpensWithBadName(String pn, String ignore) {
+        ModuleDescriptor.module("foo").opens(pn);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testOpensWithNullExports() {
+        ModuleDescriptor.module("foo").opens((Opens) null);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testOpensWithNullTargets() {
+        ModuleDescriptor.module("foo").opens("p", (Set<String>) null);
+    }
+
+    public void testOpensEqualsAndHashCode() {
+        Opens o1, o2;
+
+        o1 = opens("p");
+        o2 = opens("p");
+        assertEquals(o1, o2);
+        assertTrue(o1.hashCode() == o1.hashCode());
+
+        o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p");
+        o2 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p");
+        assertEquals(o1, o2);
+        assertTrue(o1.hashCode() == o2.hashCode());
+
+        o1 = opens("p");
+        o2 = opens("q");
+        assertNotEquals(o1, o2);
+
+        o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p");
+        o2 = opens(Set.of(), "p");
+        assertNotEquals(o1, o2);
+    }
+
+    public void testOpensToString() {
+        String s = ModuleDescriptor.module("foo")
+                .opens("p1", Set.of("bar"))
+                .build()
+                .opens()
+                .iterator()
+                .next()
+                .toString();
+        assertTrue(s.contains("p1"));
+        assertTrue(s.contains("bar"));
+    }
+
+
     // uses
 
     public void testUses() {
         Set<String> uses
-            = new Builder("foo")
+            = ModuleDescriptor.module("foo")
                 .uses("p.S")
                 .uses("q.S")
                 .build()
@@ -333,126 +582,148 @@
 
     @Test(expectedExceptions = IllegalStateException.class)
     public void testUsesWithDuplicate() {
-        new Builder("foo").uses("p.S").uses("p.S");
+        ModuleDescriptor.module("foo").uses("p.S").uses("p.S");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testUsesWithBadName(String service, String ignore) {
-        new Builder("foo").uses(service);
+        ModuleDescriptor.module("foo").uses(service);
     }
 
 
     // provides
 
     private Provides provides(String st, String pc) {
-        return new Builder("foo")
+        return ModuleDescriptor.module("foo")
             .provides(st, pc)
             .build()
             .provides()
-            .values()
             .iterator()
             .next();
     }
 
     public void testProvidesWithProvides() {
         Provides p1 = provides("p.S", "q.S1");
-        ModuleDescriptor descriptor = new Builder("m").provides(p1).build();
-        Provides p2 = descriptor.provides().get("p.S");
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m")
+                .provides(p1)
+                .build();
+        Provides p2 = descriptor.provides().iterator().next();
         assertEquals(p1, p2);
     }
 
+
     public void testProvides() {
-        Set<String> pns = new HashSet<>();
-        pns.add("q.P1");
-        pns.add("q.P2");
-
-        Map<String, Provides> map
-            = new Builder("foo")
-                .provides("p.S", pns)
+        Set<Provides> set = ModuleDescriptor.module("foo")
+                .provides("p.S", List.of("q.P1", "q.P2"))
                 .build()
                 .provides();
-        assertTrue(map.size() == 1);
+        assertTrue(set.size() == 1);
 
-        Provides p = map.values().iterator().next();
+        Provides p = set.iterator().next();
         assertEquals(p, p);
+        assertEquals(p.service(), "p.S");
         assertTrue(p.providers().size() == 2);
-        assertTrue(p.providers().contains("q.P1"));
-        assertTrue(p.providers().contains("q.P2"));
+        assertEquals(p.providers().get(0), "q.P1");
+        assertEquals(p.providers().get(1), "q.P2");
     }
 
     @Test(expectedExceptions = IllegalStateException.class )
     public void testProvidesWithDuplicateProvides() {
         Provides p = provides("p.S", "q.S2");
-        new Builder("m").provides("p.S", "q.S1").provides(p);
+        ModuleDescriptor.module("m").provides("p.S", "q.S1").provides(p);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class )
     public void testProvidesWithEmptySet() {
-        new Builder("foo").provides("p.Service", Collections.emptySet());
+        ModuleDescriptor.module("foo").provides("p.Service", Collections.emptyList());
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testProvidesWithBadService(String service, String ignore) {
-        new Builder("foo").provides(service, "p.Provider");
+        ModuleDescriptor.module("foo").provides(service, "p.Provider");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testProvidesWithBadProvider(String provider, String ignore) {
-        new Builder("foo").provides("p.Service", provider);
+        ModuleDescriptor.module("foo").provides("p.Service", provider);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testProvidesWithNullProvides() {
-        new Builder("foo").provides((Provides)null);
+        ModuleDescriptor.module("foo").provides((Provides) null);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testProvidesWithNullProviders() {
-        new Builder("foo").provides("p.S", (Set<String>) null);
+        ModuleDescriptor.module("foo").provides("p.S", (List<String>) null);
+    }
+
+    public void testProvidesEqualsAndHashCode() {
+        Provides p1, p2;
+
+        p1 = provides("p.S", "q.S1");
+        p2 = provides("p.S", "q.S1");
+        assertEquals(p1, p2);
+        assertTrue(p1.hashCode() == p2.hashCode());
+
+        p1 = provides("p.S", "q.S1");
+        p2 = provides("p.S", "q.S2");
+        assertNotEquals(p1, p2);
+
+        p1 = provides("p.S", "q.S1");
+        p2 = provides("p.S2", "q.S1");
+        assertNotEquals(p1, p2);
     }
 
-
-    // conceals
+    // contains
 
-    public void testConceals() {
-        Set<String> conceals
-            = new Builder("foo").conceals("p").conceals("q").build().conceals();
-        assertTrue(conceals.size() == 2);
-        assertTrue(conceals.contains("p"));
-        assertTrue(conceals.contains("q"));
+    public void testContains() {
+        Set<String> packages = ModuleDescriptor.module("foo")
+                .contains("p")
+                .contains("q")
+                .build()
+                .packages();
+        assertTrue(packages.size() == 2);
+        assertTrue(packages.contains("p"));
+        assertTrue(packages.contains("q"));
     }
 
-    public void testConcealsWithEmptySet() {
-        Set<String> conceals
-            = new Builder("foo").conceals(Collections.emptySet()).build().conceals();
-        assertTrue(conceals.size() == 0);
+    public void testContainsWithEmptySet() {
+        Set<String> packages = ModuleDescriptor.module("foo")
+                .contains(Collections.emptySet())
+                .build()
+                .packages();
+        assertTrue(packages.size() == 0);
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void testConcealsWithDuplicate() {
-        new Builder("foo").conceals("p").conceals("p");
+    public void testContainsWithDuplicate() {
+        ModuleDescriptor.module("foo").contains("p").contains("p");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void testConcealsWithExportedPackage() {
-        new Builder("foo").exports("p").conceals("p");
+    public void testContainsWithExportedPackage() {
+        ModuleDescriptor.module("foo").exports("p").contains("p");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
-    public void testConcealsWithBadName(String pn, String ignore) {
-        new Builder("foo").conceals(pn);
+    public void testContainsWithBadName(String pn, String ignore) {
+        ModuleDescriptor.module("foo").contains(pn);
     }
 
 
     // packages
 
     public void testPackages() {
-        Set<String> packages
-            = new Builder("foo").exports("p").conceals("q").build().packages();
+        Set<String> packages = ModuleDescriptor.module("foo")
+                .exports("p")
+                .contains("q")
+                .build()
+                .packages();
         assertTrue(packages.size() == 2);
         assertTrue(packages.contains("p"));
         assertTrue(packages.contains("q"));
@@ -462,14 +733,14 @@
     // name
 
     public void testModuleName() {
-        String mn = new Builder("foo").build().name();
+        String mn = ModuleDescriptor.module("foo").build().name();
         assertEquals(mn, "foo");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testBadModuleName(String mn, String ignore) {
-        new Builder(mn);
+        ModuleDescriptor.module(mn);
     }
 
 
@@ -477,67 +748,107 @@
 
     public void testVersion1() {
         Version v1 = Version.parse("1.0");
-        Version v2 = new Builder("foo").version(v1).build().version().get();
+        Version v2 = ModuleDescriptor.module("foo")
+                .version(v1)
+                .build()
+                .version()
+                .get();
         assertEquals(v1, v2);
     }
 
     public void testVersion2() {
         String vs = "1.0";
-        Version v1 = new Builder("foo").version(vs).build().version().get();
+        Version v1 = ModuleDescriptor.module("foo")
+                .version(vs)
+                .build()
+                .version()
+                .get();
         Version v2 = Version.parse(vs);
         assertEquals(v1, v2);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testNullVersion1() {
-        new Builder("foo").version((Version)null);
+        ModuleDescriptor.module("foo").version((Version) null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class )
     public void testNullVersion2() {
-        new Builder("foo").version((String)null);
+        ModuleDescriptor.module("foo").version((String) null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class )
     public void testEmptyVersion() {
-        new Builder("foo").version("");
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateVersion1() {
-        Version v = Version.parse("2.0");
-        new Builder("foo").version("1.0").version(v);
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateVersion2() {
-        new Builder("foo").version("1.0").version("2.0");
+        ModuleDescriptor.module("foo").version("");
     }
 
 
     // toNameAndVersion
 
     public void testToNameAndVersion() {
-        ModuleDescriptor md1 = new Builder("foo").build();
+        ModuleDescriptor md1 = ModuleDescriptor.module("foo").build();
         assertEquals(md1.toNameAndVersion(), "foo");
 
-        ModuleDescriptor md2 = new Builder("foo").version("1.0").build();
+        ModuleDescriptor md2 = ModuleDescriptor.module("foo").version("1.0").build();
         assertEquals(md2.toNameAndVersion(), "foo@1.0");
     }
 
 
-    // isAutomatic
+    // open modules
+
+    public void testOpenModules() {
+        ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
+                .requires("java.base")
+                .contains("p")
+                .build();
+        assertTrue(descriptor.isOpen());
+        assertTrue(descriptor.packages().size() == 1);
+        assertTrue(descriptor.packages().contains("p"));
+        assertTrue(descriptor.exports().isEmpty());
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensOnWeakModule1() {
+        ModuleDescriptor.openModule("foo").opens("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensOnWeakModule2() {
+        ModuleDescriptor.openModule("foo").opens("p", Set.of("bar"));
+    }
+
+    public void testIsOpen() {
+        assertFalse(ModuleDescriptor.module("m").build().isOpen());
+        assertFalse(ModuleDescriptor.automaticModule("m").build().isOpen());
+        assertTrue(ModuleDescriptor.openModule("m").build().isOpen());
+    }
+
+
+    // automatic modules
+
     public void testIsAutomatic() {
-        ModuleDescriptor descriptor = new Builder("foo").build();
-        assertFalse(descriptor.isAutomatic());
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build();
+        assertFalse(descriptor1.isAutomatic());
+
+        ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build();
+        assertFalse(descriptor2.isAutomatic());
+
+        ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build();
+        assertTrue(descriptor3.isAutomatic());
     }
 
     // isSynthetic
     public void testIsSynthetic() {
         assertFalse(Object.class.getModule().getDescriptor().isSynthetic());
 
-        ModuleDescriptor descriptor = new Builder("foo").build();
-        assertFalse(descriptor.isSynthetic());
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build();
+        assertFalse(descriptor1.isSynthetic());
+
+        ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build();
+        assertFalse(descriptor2.isSynthetic());
+
+        ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build();
+        assertFalse(descriptor3.isSynthetic());
     }
 
 
@@ -545,92 +856,71 @@
 
     public void testMainClass() {
         String mainClass
-            = new Builder("foo").mainClass("p.Main").build().mainClass().get();
+            = ModuleDescriptor.module("foo").mainClass("p.Main").build().mainClass().get();
         assertEquals(mainClass, "p.Main");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testMainClassWithBadName(String mainClass, String ignore) {
-        Builder builder = new Builder("foo");
+        Builder builder = ModuleDescriptor.module("foo");
         builder.mainClass(mainClass);
     }
 
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateMainClass() {
-        new Builder("foo").mainClass("p.Main").mainClass("p.Main");
-    }
-
 
     // osName
 
     public void testOsName() {
-        String osName = new Builder("foo").osName("Linux").build().osName().get();
+        String osName = ModuleDescriptor.module("foo").osName("Linux").build().osName().get();
         assertEquals(osName, "Linux");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testNullOsName() {
-        new Builder("foo").osName(null);
+        ModuleDescriptor.module("foo").osName(null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testEmptyOsName() {
-        new Builder("foo").osName("");
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateOsName() {
-        new Builder("foo").osName("Linux").osName("Linux");
+        ModuleDescriptor.module("foo").osName("");
     }
 
 
     // osArch
 
     public void testOsArch() {
-        String osArch = new Builder("foo").osName("arm").build().osName().get();
+        String osArch = ModuleDescriptor.module("foo").osName("arm").build().osName().get();
         assertEquals(osArch, "arm");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testNullOsArch() {
-        new Builder("foo").osArch(null);
+        ModuleDescriptor.module("foo").osArch(null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testEmptyOsArch() {
-        new Builder("foo").osArch("");
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateOsArch() {
-        new Builder("foo").osArch("arm").osArch("arm");
+        ModuleDescriptor.module("foo").osArch("");
     }
 
 
     // osVersion
 
     public void testOsVersion() {
-        String osVersion = new Builder("foo").osName("11.2").build().osName().get();
+        String osVersion = ModuleDescriptor.module("foo").osName("11.2").build().osName().get();
         assertEquals(osVersion, "11.2");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testNullOsVersion() {
-        new Builder("foo").osVersion(null);
+        ModuleDescriptor.module("foo").osVersion(null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testEmptyOsVersion() {
-        new Builder("foo").osVersion("");
+        ModuleDescriptor.module("foo").osVersion("");
     }
 
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateOsVersion() {
-        new Builder("foo").osVersion("11.2").osVersion("11.2");
-    }
-
-
     // reads
 
     private static InputStream EMPTY_INPUT_STREAM = new InputStream() {
@@ -647,7 +937,8 @@
         }
     };
 
-    public void testRead() throws Exception {
+    // basic test reading module-info.class
+    public void testRead1() throws Exception {
         Module base = Object.class.getModule();
 
         try (InputStream in = base.getResourceAsStream("module-info.class")) {
@@ -664,9 +955,80 @@
         }
     }
 
-    public void testReadsWithPackageFinder() {
-        // TBD: Need way to write a module-info.class without a
-        // ConcealedPackages attribute
+    /**
+     * Test reading a module-info.class that has a module name, requires,
+     * and qualified exports with module names that are not supported in the
+     * Java Language.
+     */
+    public void testRead2() throws Exception {
+        // use non-public constructor to create a Builder that is not strict
+        Constructor<?> ctor = Builder.class.getDeclaredConstructor(String.class, boolean.class);
+        ctor.setAccessible(true);
+
+        Builder builder = (ModuleDescriptor.Builder) ctor.newInstance("m?1", false);
+        ModuleDescriptor descriptor = builder
+                .requires("java.base")
+                .requires("-m1")
+                .exports("p", Set.of("m2-"))
+                .build();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ModuleInfoWriter.write(descriptor, baos);
+        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
+
+        descriptor = ModuleDescriptor.read(bb);
+        assertEquals(descriptor.name(), "m?1");
+
+        Set<String> requires = descriptor.requires()
+                .stream()
+                .map(Requires::name)
+                .collect(Collectors.toSet());
+        assertTrue(requires.size() == 2);
+        assertTrue(requires.contains("java.base"));
+        assertTrue(requires.contains("-m1"));
+
+        assertTrue(descriptor.exports().size() == 1);
+        Exports e = descriptor.exports().iterator().next();
+        assertTrue(e.targets().size() == 1);
+        assertTrue(e.targets().contains("m2-"));
+    }
+
+    /**
+     * Test ModuleDescriptor with a packager finder
+     */
+    public void testReadsWithPackageFinder() throws Exception {
+        ModuleDescriptor descriptor = ModuleDescriptor.module("foo")
+                .requires("java.base")
+                .build();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ModuleInfoWriter.write(descriptor, baos);
+        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
+
+        descriptor = ModuleDescriptor.read(bb, () -> Set.of("p", "q"));
+
+        assertTrue(descriptor.packages().size() == 2);
+        assertTrue(descriptor.packages().contains("p"));
+        assertTrue(descriptor.packages().contains("q"));
+    }
+
+    /**
+     * Test ModuleDescriptor with a packager finder that doesn't return the
+     * complete set of packages.
+     */
+    @Test(expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testReadsWithBadPackageFinder() throws Exception {
+        ModuleDescriptor descriptor = ModuleDescriptor.module("foo")
+                .requires("java.base")
+                .exports("p")
+                .build();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ModuleInfoWriter.write(descriptor, baos);
+        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
+
+        // package finder returns a set that doesn't include p
+        ModuleDescriptor.read(bb, () -> Set.of("q"));
     }
 
     @Test(expectedExceptions = InvalidModuleDescriptorException.class)
@@ -689,7 +1051,7 @@
     @Test(expectedExceptions = InvalidModuleDescriptorException.class)
     public void testReadOfJavaBaseWithRequires() {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("java.base")
+            = ModuleDescriptor.module("java.base")
                 .requires("other")
                 .build();
         ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
@@ -699,7 +1061,7 @@
     // The requires table must have an entry for java.base
     @Test(expectedExceptions = InvalidModuleDescriptorException.class)
     public void testReadWithEmptyRequires() {
-        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build();
         ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
         ModuleDescriptor.read(bb);
     }
@@ -708,14 +1070,13 @@
     @Test(expectedExceptions = InvalidModuleDescriptorException.class)
     public void testReadWithNoRequiresBase() {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
         ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
         ModuleDescriptor.read(bb);
     }
 
-
     public void testReadWithNull() throws Exception {
         Module base = Object.class.getModule();
 
@@ -751,22 +1112,22 @@
     // equals/hashCode/compareTo/toString
 
     public void testEqualsAndHashCode() {
-        ModuleDescriptor md1 = new Builder("foo").build();
-        ModuleDescriptor md2 = new Builder("foo").build();
+        ModuleDescriptor md1 = ModuleDescriptor.module("foo").build();
+        ModuleDescriptor md2 = ModuleDescriptor.module("foo").build();
         assertEquals(md1, md1);
         assertEquals(md1.hashCode(), md2.hashCode());
     }
 
     public void testCompare() {
-        ModuleDescriptor md1 = new Builder("foo").build();
-        ModuleDescriptor md2 = new Builder("bar").build();
+        ModuleDescriptor md1 = ModuleDescriptor.module("foo").build();
+        ModuleDescriptor md2 = ModuleDescriptor.module("bar").build();
         int n = "foo".compareTo("bar");
         assertTrue(md1.compareTo(md2) == n);
         assertTrue(md2.compareTo(md1) == -n);
     }
 
     public void testToString() {
-        String s = new Builder("m1").requires("m2").exports("p1").build().toString();
+        String s = ModuleDescriptor.module("m1").requires("m2").exports("p1").build().toString();
         assertTrue(s.contains("m1"));
         assertTrue(s.contains("m2"));
         assertTrue(s.contains("p1"));
--- a/jdk/test/java/lang/module/ModuleFinderTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/module/ModuleFinderTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -335,7 +335,7 @@
 
         ModuleFinder finder = ModuleFinder.of(jar);
         Optional<ModuleReference> mref = finder.find("m");
-        assertTrue(mref.isPresent(), "m not found");
+        assertTrue(mref.isPresent(), "m1 not found");
 
         ModuleDescriptor descriptor = mref.get().descriptor();
 
@@ -748,7 +748,7 @@
             vs = mid.substring(i+1);
         }
         ModuleDescriptor.Builder builder
-            = new ModuleDescriptor.Builder(mn).requires("java.base");
+            = ModuleDescriptor.module(mn).requires("java.base");
         if (vs != null)
             builder.version(vs);
         return builder.build();
--- a/jdk/test/java/lang/module/ModuleReferenceTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/module/ModuleReferenceTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -45,10 +45,10 @@
 
     public void testBasic() throws Exception {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m")
+            = ModuleDescriptor.module("m")
                 .exports("p")
                 .exports("q")
-                .conceals("p.internal")
+                .contains("p.internal")
                 .build();
 
         URI uri = URI.create("module:/m");
@@ -76,7 +76,7 @@
 
     public void testNullLocation() {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m")
+            = ModuleDescriptor.module("m")
                 .exports("p")
                 .build();
         Supplier<ModuleReader> supplier = makeSupplier();
@@ -86,7 +86,7 @@
 
     @Test(expectedExceptions = { NullPointerException.class })
     public void testNullSupplier() throws Exception {
-        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m").build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m").build();
         URI location = URI.create("module:/m");
         new ModuleReference(descriptor, location, null);
     }
@@ -94,11 +94,11 @@
 
     public void testEqualsAndHashCode() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .build();
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .build();
 
@@ -121,7 +121,7 @@
 
 
     public void testToString() {
-        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build();
         URI uri = URI.create("module:/m1");
         Supplier<ModuleReader> supplier = makeSupplier();
         ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
--- a/jdk/test/java/lang/module/MultiReleaseJarTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/module/MultiReleaseJarTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -80,7 +80,7 @@
     public void testBasic() throws Exception {
         String name = "m1";
 
-        ModuleDescriptor descriptor = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .build();
 
@@ -117,12 +117,12 @@
     public void testModuleInfoInVersionedSection() throws Exception {
         String name = "m1";
 
-        ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .build();
 
         // module descriptor for versioned section
-        ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor2 = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .requires("jdk.unsupported")
                 .build();
@@ -188,12 +188,12 @@
     public void testModuleReader() throws Exception {
         String name = "m1";
 
-        ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .build();
 
         // module descriptor for versioned section
-        ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor2 = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .requires("jdk.unsupported")
                 .build();
--- a/jdk/test/java/lang/ref/FinalizerHistogramTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/ref/FinalizerHistogramTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -31,6 +31,7 @@
 /*
  * @test
  * @summary Unit test for FinalizerHistogram
+ * @modules java.base/java.lang.ref:open
  * @run main FinalizerHistogramTest
  */
 
--- a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,8 @@
 /**
  * @test
  * @build ModuleSetAccessibleTest
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/java.lang:open
+ *          java.base/jdk.internal.misc:+open
  * @run testng ModuleSetAccessibleTest
  * @summary Test java.lang.reflect.AccessibleObject with modules
  */
@@ -142,81 +143,6 @@
 
 
     /**
-     * Test that only public members of java.lang.reflect.Module can be make
-     * accessible.
-     */
-    public void testJavaLangReflectModule() throws Exception {
-
-        // non-public constructor
-        Constructor<?> ctor
-            = Module.class.getDeclaredConstructor(ClassLoader.class,
-                                                  ModuleDescriptor.class);
-        AccessibleObject[] ctors = { ctor };
-
-        try {
-            ctor.setAccessible(true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        try {
-            AccessibleObject.setAccessible(ctors, true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        // should succeed
-        ctor.setAccessible(false);
-        AccessibleObject.setAccessible(ctors, false);
-
-
-        // public method
-        Method method = Module.class.getMethod("addReads", Module.class);
-        AccessibleObject[] methods = { method };
-        method.setAccessible(true);
-        AccessibleObject.setAccessible(methods, true);
-        method.setAccessible(false);
-        AccessibleObject.setAccessible(methods, false);
-
-        // non-public method
-        method = Module.class.getDeclaredMethod("implAddReadsNoSync", Module.class);
-        methods[0] = method;
-
-        try {
-            method.setAccessible(true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        try {
-            AccessibleObject.setAccessible(methods, true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        // should succeed
-        method.setAccessible(false);
-        AccessibleObject.setAccessible(methods, false);
-
-
-        // non-public field
-        Field field = Module.class.getDeclaredField("name");
-        AccessibleObject[] fields = { field };
-
-        try {
-            field.setAccessible(true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        try {
-            AccessibleObject.setAccessible(fields, true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        // should succeed
-        field.setAccessible(false);
-        AccessibleObject.setAccessible(fields, false);
-
-    }
-
-
-    /**
      * Test that the Class constructor cannot be make accessible.
      */
     public void testJavaLangClass() throws Exception {
--- a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,12 +32,14 @@
 
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleFinder;
 import java.lang.reflect.Layer;
 import java.lang.reflect.LayerInstantiationException;
 import java.lang.reflect.Module;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -53,7 +55,7 @@
     public void testEmpty() {
         Layer emptyLayer = Layer.empty();
 
-        assertFalse(emptyLayer.parent().isPresent());
+        assertTrue(emptyLayer.parents().isEmpty());
 
         assertTrue(emptyLayer.configuration() == Configuration.empty());
 
@@ -97,8 +99,9 @@
         // findLoader
         assertTrue(bootLayer.findLoader("java.base") == null);
 
-        // parent
-        assertTrue(bootLayer.parent().get() == Layer.empty());
+        // parents
+        assertTrue(bootLayer.parents().size() == 1);
+        assertTrue(bootLayer.parents().get(0) == Layer.empty());
     }
 
 
@@ -107,18 +110,18 @@
      */
     public void testLayerOnEmpty() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .exports("p1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m3")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .build();
 
         ModuleFinder finder
@@ -178,8 +181,9 @@
             assertTrue(false);
         } catch (IllegalArgumentException ignore) { }
 
-        // parent
-        assertTrue(layer.parent().get() == Layer.empty());
+        // parents
+        assertTrue(layer.parents().size() == 1);
+        assertTrue(layer.parents().get(0) == Layer.empty());
     }
 
 
@@ -188,14 +192,14 @@
      */
     public void testLayerOnBoot() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .requires("java.base")
                 .exports("p1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("java.base")
                 .build();
 
@@ -241,8 +245,9 @@
         assertTrue(layer.findLoader("m2") == loader);
         assertTrue(layer.findLoader("java.base") == null);
 
-        // parent
-        assertTrue(layer.parent().get() == Layer.boot());
+        // parents
+        assertTrue(layer.parents().size() == 1);
+        assertTrue(layer.parents().get(0) == Layer.boot());
     }
 
 
@@ -250,16 +255,16 @@
      * Exercise Layer defineModules with a configuration of two modules that
      * have the same module-private package.
      */
-    public void testSameConcealedPackage() {
+    public void testPackageContainedInSelfAndOther() {
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
-                .conceals("p")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .conceals("p")
+            = ModuleDescriptor.module("m2")
+                .contains("p")
                 .build();
 
         ModuleFinder finder
@@ -288,22 +293,22 @@
 
         // m1 reads m2, m2 exports p to m1
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .exports("p", "m1")
+            =  ModuleDescriptor.module("m2")
+                .exports("p", Set.of("m1"))
                 .build();
 
         // m3 reads m4, m4 exports p to m3
         ModuleDescriptor descriptor3
-            =  new ModuleDescriptor.Builder("m3")
+            =  ModuleDescriptor.module("m3")
                 .requires("m4")
                 .build();
         ModuleDescriptor descriptor4
-            =  new ModuleDescriptor.Builder("m4")
-                .exports("p", "m3")
+            =  ModuleDescriptor.module("m4")
+                .exports("p", Set.of("m3"))
                 .build();
 
         ModuleFinder finder
@@ -325,7 +330,7 @@
         map.put("m1", loader1);
         map.put("m2", loader1);
         map.put("m3", loader2);
-        map.put("m3", loader2);
+        map.put("m4", loader2);
         Layer.empty().defineModules(cf, map::get);
 
         // same loader
@@ -338,20 +343,20 @@
 
 
     /**
-     * Exercise Layer defineModules with a configuration that contains a module
-     * that has a concealed package that is the same name as a non-exported
-     * package in a parent layer.
+     * Exercise Layer defineModules with a configuration with a module that
+     * contains a package that is the same name as a non-exported package in
+     * a parent layer.
      */
-    public void testConcealSamePackageAsBootLayer() {
+    public void testContainsSamePackageAsBootLayer() {
 
         // check assumption that java.base contains sun.launcher
         ModuleDescriptor base = Object.class.getModule().getDescriptor();
-        assertTrue(base.conceals().contains("sun.launcher"));
+        assertTrue(base.packages().contains("sun.launcher"));
 
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                .requires("java.base")
-               .conceals("sun.launcher")
+               .contains("sun.launcher")
                .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor);
@@ -370,20 +375,20 @@
      * Test layers with implied readability.
      *
      * The test consists of three configurations:
-     * - Configuration/layer1: m1, m2 requires public m1
+     * - Configuration/layer1: m1, m2 requires transitive m1
      * - Configuration/layer2: m3 requires m1
      */
     public void testImpliedReadabilityWithLayers1() {
 
-        // cf1: m1 and m2, m2 requires public m1
+        // cf1: m1 and m2, m2 requires transitive m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -397,7 +402,7 @@
         // cf2: m3, m3 requires m2
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -408,8 +413,11 @@
         ClassLoader cl2 = new ClassLoader() { };
         Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
 
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
+        assertTrue(layer1.parents().size() == 1);
+        assertTrue(layer1.parents().get(0) == Layer.empty());
+
+        assertTrue(layer2.parents().size() == 1);
+        assertTrue(layer2.parents().get(0) == layer1);
 
         Module m1 = layer2.findModule("m1").get();
         Module m2 = layer2.findModule("m2").get();
@@ -442,14 +450,14 @@
      *
      * The test consists of three configurations:
      * - Configuration/layer1: m1
-     * - Configuration/layer2: m2 requires public m3, m3 requires m2
+     * - Configuration/layer2: m2 requires transitive m3, m3 requires m2
      */
     public void testImpliedReadabilityWithLayers2() {
 
         // cf1: m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -460,15 +468,15 @@
         Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
 
 
-        // cf2: m2, m3: m2 requires public m1, m3 requires m2
+        // cf2: m2, m3: m2 requires transitive m1, m3 requires m2
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -479,8 +487,11 @@
         ClassLoader cl2 = new ClassLoader() { };
         Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
 
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
+        assertTrue(layer1.parents().size() == 1);
+        assertTrue(layer1.parents().get(0) == Layer.empty());
+
+        assertTrue(layer2.parents().size() == 1);
+        assertTrue(layer2.parents().get(0) == layer1);
 
         Module m1 = layer2.findModule("m1").get();
         Module m2 = layer2.findModule("m2").get();
@@ -509,7 +520,7 @@
      *
      * The test consists of three configurations:
      * - Configuration/layer1: m1
-     * - Configuration/layer2: m2 requires public m1
+     * - Configuration/layer2: m2 requires transitive m1
      * - Configuration/layer3: m3 requires m1
      */
     public void testImpliedReadabilityWithLayers3() {
@@ -517,7 +528,7 @@
         // cf1: m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -528,11 +539,11 @@
         Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
 
 
-        // cf2: m2 requires public m1
+        // cf2: m2 requires transitive m1
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
@@ -546,7 +557,7 @@
         // cf3: m3 requires m2
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -557,9 +568,14 @@
         ClassLoader cl3 = new ClassLoader() { };
         Layer layer3 = layer2.defineModules(cf3, mn -> cl3);
 
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
-        assertTrue(layer3.parent().get() == layer2);
+        assertTrue(layer1.parents().size() == 1);
+        assertTrue(layer1.parents().get(0) == Layer.empty());
+
+        assertTrue(layer2.parents().size() == 1);
+        assertTrue(layer2.parents().get(0) == layer1);
+
+        assertTrue(layer3.parents().size() == 1);
+        assertTrue(layer3.parents().get(0) == layer2);
 
         Module m1 = layer3.findModule("m1").get();
         Module m2 = layer3.findModule("m2").get();
@@ -587,20 +603,20 @@
      * Test layers with implied readability.
      *
      * The test consists of two configurations:
-     * - Configuration/layer1: m1, m2 requires public m1
-     * - Configuration/layer2: m3 requires public m2, m4 requires m3
+     * - Configuration/layer1: m1, m2 requires transitive m1
+     * - Configuration/layer2: m3 requires transitive m2, m4 requires m3
      */
     public void testImpliedReadabilityWithLayers4() {
 
-        // cf1: m1, m2 requires public m1
+        // cf1: m1, m2 requires transitive m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -611,15 +627,15 @@
         Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
 
 
-        // cf2: m3 requires public m2, m4 requires m3
+        // cf2: m3 requires transitive m2, m4 requires m3
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m2")
+            = ModuleDescriptor.module("m3")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2")
                 .build();
 
         ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4")
+            = ModuleDescriptor.module("m4")
                 .requires("m3")
                 .build();
 
@@ -631,8 +647,11 @@
         ClassLoader cl2 = new ClassLoader() { };
         Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
 
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
+        assertTrue(layer1.parents().size() == 1);
+        assertTrue(layer1.parents().get(0) == Layer.empty());
+
+        assertTrue(layer2.parents().size() == 1);
+        assertTrue(layer2.parents().get(0) == layer1);
 
         Module m1 = layer2.findModule("m1").get();
         Module m2 = layer2.findModule("m2").get();
@@ -675,7 +694,7 @@
     public void testModuleAlreadyDefinedToLoader() {
 
         ModuleDescriptor md
-            = new ModuleDescriptor.Builder("m")
+            = ModuleDescriptor.module("m")
                 .requires("java.base")
                 .build();
 
@@ -704,14 +723,14 @@
     public void testPackageAlreadyInNamedModule() {
 
         ModuleDescriptor md1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
                 .requires("java.base")
                 .build();
 
         ModuleDescriptor md2
-            = new ModuleDescriptor.Builder("m2")
-                .conceals("p")
+            = ModuleDescriptor.module("m2")
+                .contains("p")
                 .requires("java.base")
                 .build();
 
@@ -749,8 +768,8 @@
         assertFalse(c.getModule().isNamed());  // in unnamed module
 
         ModuleDescriptor md
-            = new ModuleDescriptor.Builder("m")
-                .conceals(c.getPackageName())
+            = ModuleDescriptor.module("m")
+                .contains(c.getPackageName())
                 .requires("java.base")
                 .build();
 
@@ -768,7 +787,7 @@
      */
     public void testLayerWithJavaBase() {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("java.base")
+            = ModuleDescriptor.module("java.base")
                 .exports("java.lang")
                 .build();
 
@@ -782,12 +801,7 @@
         ClassLoader scl = ClassLoader.getSystemClassLoader();
 
         try {
-            Layer.boot().defineModules(cf, loader -> null );
-            assertTrue(false);
-        } catch (LayerInstantiationException e) { }
-
-        try {
-            Layer.boot().defineModules(cf, loader -> new ClassLoader() { });
+            Layer.boot().defineModules(cf, mn -> new ClassLoader() { });
             assertTrue(false);
         } catch (LayerInstantiationException e) { }
 
@@ -804,13 +818,81 @@
 
 
     /**
+     * Attempt to create a Layer with a module containing a "java." package.
+     * This should only be allowed when the module is defined to the platform
+     * class loader.
+     */
+    @Test(enabled = false)
+    public void testLayerWithJavaPackage() {
+        ModuleDescriptor descriptor
+            = ModuleDescriptor.module("foo")
+                .contains("java.foo")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor);
+
+        Configuration cf = Layer.boot()
+                .configuration()
+                .resolveRequires(finder, ModuleFinder.of(), Set.of("foo"));
+        assertTrue(cf.modules().size() == 1);
+
+        ClassLoader pcl = ClassLoader.getPlatformClassLoader();
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        try {
+            Layer.boot().defineModules(cf, mn -> new ClassLoader() { });
+            assertTrue(false);
+        } catch (LayerInstantiationException e) { }
+
+        try {
+            Layer.boot().defineModulesWithOneLoader(cf, scl);
+            assertTrue(false);
+        } catch (LayerInstantiationException e) { }
+
+        try {
+            Layer.boot().defineModulesWithManyLoaders(cf, scl);
+            assertTrue(false);
+        } catch (LayerInstantiationException e) { }
+
+        // create layer with module defined to platform class loader
+        Layer layer = Layer.boot().defineModules(cf, mn -> pcl);
+        Optional<Module> om = layer.findModule("foo");
+        assertTrue(om.isPresent());
+        Module foo = om.get();
+        assertTrue(foo.getClassLoader() == pcl);
+        assertTrue(foo.getPackages().length == 1);
+        assertTrue(foo.getPackages()[0].equals("java.foo"));
+    }
+
+
+    /**
+     * Attempt to create a Layer with a module defined to the boot loader
+     */
+    @Test(expectedExceptions = { LayerInstantiationException.class })
+    public void testLayerWithBootLoader() {
+        ModuleDescriptor descriptor
+            = ModuleDescriptor.module("m1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor);
+
+        Configuration cf = Layer.boot()
+            .configuration()
+            .resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
+        assertTrue(cf.modules().size() == 1);
+
+        Layer.boot().defineModules(cf, mn -> null );
+    }
+
+
+    /**
      * Parent of configuration != configuration of parent Layer
      */
     @Test(expectedExceptions = { IllegalArgumentException.class })
     public void testIncorrectParent1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("java.base")
                 .build();
 
@@ -831,7 +913,7 @@
     public void testIncorrectParent2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
--- a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,6 +30,8 @@
  * @summary Tests for java.lang.reflect.Layer@createWithXXX methods
  */
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
@@ -38,8 +40,10 @@
 import java.lang.reflect.LayerInstantiationException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Module;
+import java.net.URL;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -263,10 +267,10 @@
     public void testOverlappingPackages() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").exports("p").build();
+            = ModuleDescriptor.module("m1").exports("p").build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2").exports("p").build();
+            = ModuleDescriptor.module("m2").exports("p").build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
 
@@ -297,10 +301,10 @@
     public void testSplitDelegation() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").exports("p").build();
+            = ModuleDescriptor.module("m1").exports("p").build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2").exports("p").build();
+            = ModuleDescriptor.module("m2").exports("p").build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
 
@@ -312,10 +316,10 @@
         checkLayer(layer1, "m1", "m2");
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3").requires("m1").build();
+            = ModuleDescriptor.module("m3").requires("m1").build();
 
         ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4").requires("m2").build();
+            = ModuleDescriptor.module("m4").requires("m2").build();
 
         ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
 
@@ -568,6 +572,48 @@
     }
 
 
+    /**
+     * Basic test of resource loading with a class loader created by
+     * Layer.defineModulesWithOneLoader.
+     */
+    public void testResourcesOneLoader() throws Exception {
+        Configuration cf = resolveRequires("m1");
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl);
+        ClassLoader loader = layer.findLoader("m1");
+        testResourceLoading(loader, "p/Main.class");
+    }
+
+    /**
+     * Basic test of resource loading with a class loader created by
+     * Layer.defineModulesWithOneLoader.
+     */
+    public void testResourcesManyLoaders() throws Exception {
+        Configuration cf = resolveRequires("m1");
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl);
+        ClassLoader loader = layer.findLoader("m1");
+        testResourceLoading(loader, "p/Main.class");
+    }
+
+    /**
+     * Test that a resource is located by a class loader.
+     */
+    private void testResourceLoading(ClassLoader loader, String name)
+        throws IOException
+    {
+        URL url = loader.getResource(name);
+        assertNotNull(url);
+
+        try (InputStream in = loader.getResourceAsStream(name)) {
+            assertNotNull(in);
+        }
+
+        Enumeration<URL> urls = loader.getResources(name);
+        assertTrue(urls.hasMoreElements());
+    }
+
+
     // -- supporting methods --
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,196 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @build LayerControllerTest ModuleUtils
+ * @run testng LayerControllerTest
+ * @summary Basic tests for java.lang.reflect.Layer.Controller
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.util.List;
+import java.util.Set;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class LayerControllerTest {
+
+    /**
+     * Creates a Controller for a module layer containing modules m1 and m2.
+     * Module m1 contains p1, reads java.base, does not export/open any package
+     * Module m2 contains p2, reads java.base, does not export/open any package
+     */
+    private Layer.Controller createTestLayer() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .contains("p1")
+                .requires("java.base")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires("java.base")
+                .contains("p2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+        Layer bootLayer = Layer.boot();
+
+        Configuration cf = bootLayer.configuration()
+                .resolveRequires(finder, ModuleFinder.of(), Set.of("m1", "m2"));
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer.Controller controller
+                = Layer.defineModulesWithOneLoader(cf, List.of(bootLayer), scl);
+
+        Layer layer = controller.layer();
+
+        assertTrue(layer.modules().size() == 2);
+        assertTrue(layer.findModule("m1").isPresent());
+        assertTrue(layer.findModule("m2").isPresent());
+
+        return controller;
+    }
+
+    /**
+     * Basic test of Layer.Controller to update modules m1 and m2 to read and
+     * open packages to each other.
+     */
+    public void testBasic() {
+        Layer.Controller controller = createTestLayer();
+        Layer layer = controller.layer();
+        Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new);
+        Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new);
+
+        assertFalse(m1.canRead(m2));
+        assertFalse(m1.isExported("p1"));
+        assertFalse(m1.isOpen("p1"));
+        assertFalse(m1.isExported("p1", m2));
+        assertFalse(m1.isOpen("p1", m2));
+
+        assertFalse(m2.canRead(m1));
+        assertFalse(m2.isExported("p2"));
+        assertFalse(m2.isOpen("p2"));
+        assertFalse(m2.isExported("p2", m1));
+        assertFalse(m2.isOpen("p2", m1));
+
+        // update m1 to read m2
+        assertTrue(controller.addReads(m1, m2) == controller);
+        assertTrue(m1.canRead(m2));
+        assertFalse(m2.canRead(m1));
+
+        // update m2 to read m1
+        assertTrue(controller.addReads(m2, m1) == controller);
+        assertTrue(m1.canRead(m2));
+        assertTrue(m1.canRead(m1));
+
+        // update m1 to open p1 to m2
+        assertTrue(controller.addOpens(m1, "p1", m2) == controller);
+        assertTrue(m1.isExported("p1", m2));
+        assertTrue(m1.isOpen("p1", m2));
+        assertFalse(m1.isExported("p1"));
+        assertFalse(m1.isOpen("p1"));
+
+        // update m2 to open p2 to m1
+        assertTrue(controller.addOpens(m2, "p2", m1) == controller);
+        assertTrue(m2.isExported("p2", m1));
+        assertTrue(m2.isOpen("p2", m1));
+        assertFalse(m2.isExported("p2"));
+        assertFalse(m2.isOpen("p2"));
+    }
+
+    /**
+     * Test invalid argument handling
+     */
+    public void testBadArguments() {
+        Layer.Controller controller = createTestLayer();
+        Layer layer = controller.layer();
+        Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new);
+        Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new);
+        Module base = Object.class.getModule();
+
+        // java.base is not in layer
+        try {
+            controller.addReads(base, m2);
+            assertTrue(false);
+        } catch (IllegalArgumentException expected) { }
+
+        // java.base is not in layer
+        try {
+            controller.addOpens(base, "java.lang", m2);
+            assertTrue(false);
+        } catch (IllegalArgumentException expected) { }
+
+        // m1 does not contain java.lang
+        try {
+            controller.addOpens(m1, "java.lang", m2);
+            assertTrue(false);
+        } catch (IllegalArgumentException expected) { }
+    }
+
+    /**
+     * Test null handling
+     */
+    public void testNulls() {
+        Layer.Controller controller = createTestLayer();
+        Layer layer = controller.layer();
+        Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new);
+        Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new);
+        assertTrue(m1 != null);
+        assertTrue(m2 != null);
+
+        try {
+            controller.addReads(null, m2);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            controller.addReads(m1, null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            controller.addOpens(null, "p1", m2);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            controller.addOpens(m1, null, m2);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            controller.addOpens(m1, "p1", null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,157 @@
+/*
+ * 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.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import jdk.internal.module.ClassFileAttributes;
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.module
+ *          java.xml
+ * @run testng AnnotationsTest
+ * @summary Basic test of annotations on modules
+ */
+
+public class AnnotationsTest {
+
+    /**
+     * Test that there are no annotations on an unnamed module.
+     */
+    @Test
+    public void testUnnamedModule() {
+        Module module = this.getClass().getModule();
+        assertTrue(module.getAnnotations().length == 0);
+    }
+
+    /**
+     * Test loading a module with a RuntimeVisibleAnnotation attribute.
+     * The test copies the module-info.class for java.xml, adds the attribute,
+     * and then loads the updated module.
+     */
+    @Test
+    public void testNamedModule() throws IOException {
+
+        // "deprecate" java.xml
+        Path dir = Files.createTempDirectory("mods");
+        deprecateModule("java.xml", true, "9", dir);
+
+        // "load" the cloned java.xml
+        Module module = loadModule(dir, "java.xml");
+
+        // check the annotation is present
+        assertTrue(module.isAnnotationPresent(Deprecated.class));
+        Deprecated d = module.getAnnotation(Deprecated.class);
+        assertNotNull(d, "@Deprecated not found");
+        assertTrue(d.forRemoval());
+        assertEquals(d.since(), "9");
+        Annotation[] a = module.getAnnotations();
+        assertTrue(a.length == 1);
+        assertTrue(a[0] instanceof Deprecated);
+    }
+
+
+    /**
+     * Copy the module-info.class for the given module, add the
+     * Deprecated annotation, and write the updated module-info.class
+     * to a directory.
+     */
+    static void deprecateModule(String name,
+                                boolean forRemoval,
+                                String since,
+                                Path output) throws IOException {
+        Module module = Layer.boot().findModule(name).orElse(null);
+        assertNotNull(module, name + " not found");
+
+        InputStream in = module.getResourceAsStream("module-info.class");
+        assertNotNull(in, "No module-info.class for " + name);
+
+        try (in) {
+            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                             + ClassWriter.COMPUTE_FRAMES);
+
+            ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) { };
+
+            ClassReader cr = new ClassReader(in);
+
+            List<Attribute> attrs = new ArrayList<>();
+            attrs.add(new ClassFileAttributes.ModuleAttribute());
+            attrs.add(new ClassFileAttributes.ModulePackagesAttribute());
+            attrs.add(new ClassFileAttributes.ModuleVersionAttribute());
+            attrs.add(new ClassFileAttributes.ModuleTargetAttribute());
+            cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
+
+            AnnotationVisitor annotationVisitor
+                = cv.visitAnnotation("Ljava/lang/Deprecated;", true);
+            annotationVisitor.visit("forRemoval", forRemoval);
+            annotationVisitor.visit("since", since);
+            annotationVisitor.visitEnd();
+
+            byte[] bytes = cw.toByteArray();
+            Path mi = output.resolve("module-info.class");
+            Files.write(mi, bytes);
+        }
+    }
+
+    /**
+     * Load the module of the given name in the given directory into a
+     * child layer.
+     */
+    static Module loadModule(Path dir, String name) throws IOException {
+        ModuleFinder finder = ModuleFinder.of(dir);
+
+        Layer bootLayer = Layer.boot();
+
+        Configuration cf = bootLayer.configuration()
+                .resolveRequires(finder, ModuleFinder.of(), Set.of(name));
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
+
+        Module module = layer.findModule(name).orElse(null);
+        assertNotNull(module, name + " not loaded");
+        return module;
+    }
+}
--- a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -174,8 +174,24 @@
         // isExported
         assertTrue(base.isExported("java.lang"));
         assertTrue(base.isExported("java.lang", thisModule));
+        assertTrue(base.isExported("java.lang", base));
+        assertFalse(base.isExported("jdk.internal.misc"));
+        assertFalse(base.isExported("jdk.internal.misc", thisModule));
+        assertTrue(base.isExported("jdk.internal.misc", base));
         assertFalse(base.isExported("java.wombat"));
         assertFalse(base.isExported("java.wombat", thisModule));
+        assertFalse(base.isExported("java.wombat", base));
+
+        // isOpen
+        assertFalse(base.isOpen("java.lang"));
+        assertFalse(base.isOpen("java.lang", thisModule));
+        assertTrue(base.isOpen("java.lang", base));
+        assertFalse(base.isOpen("jdk.internal.misc"));
+        assertFalse(base.isOpen("jdk.internal.misc", thisModule));
+        assertTrue(base.isOpen("jdk.internal.misc", base));
+        assertFalse(base.isOpen("java.wombat"));
+        assertFalse(base.isOpen("java.wombat", thisModule));
+        assertFalse(base.isOpen("java.wombat", base));
     }
 
 
--- a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @modules java.logging
+ * @modules jdk.compiler
  * @summary Test java.lang.reflect.Module methods that specify permission checks
  * @run main/othervm -Djava.security.policy=${test.src}/allow.policy WithSecurityManager allow
  * @run main/othervm WithSecurityManager deny
@@ -47,8 +47,8 @@
 public class WithSecurityManager {
 
     // a module that will be loaded into a child layer
-    static final String ANOTHER_MODULE          = "java.logging";
-    static final String ANOTHER_MODULE_RESOURCE = "java/util/logging/Logger.class";
+    static final String ANOTHER_MODULE          = "jdk.compiler";
+    static final String ANOTHER_MODULE_RESOURCE = "com/sun/tools/javac/Main.class";
 
     public static void main(String[] args) throws IOException {
         boolean allow = args[0].equals("allow");
@@ -144,4 +144,4 @@
             throw new RuntimeException();
     }
 
-}
\ No newline at end of file
+}
--- a/jdk/test/java/lang/reflect/Module/access/AccessTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Module/access/AccessTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,8 +38,8 @@
  * @modules jdk.compiler
  * @build AccessTest CompilerUtils jdk.testlibrary.*
  * @run testng AccessTest
- * @summary Driver for test that checks access to public members in exported
- *          and non-exported packages.
+ * @summary Driver for test that checks access to access to types in
+ *          exported and non-exported packages.
  */
 
 @Test
@@ -74,6 +74,7 @@
         int exitValue
             = executeTestJava("--module-path", MODS_DIR.toString(),
                               "--add-modules", "target",
+                              "-Dsun.reflect.enableStrictMode=true",
                               "-m", "test/test.Main")
                 .outputTo(System.out)
                 .errorTo(System.out)
--- a/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -22,5 +22,6 @@
  */
 
 module target {
-    exports p;
+    exports p1;
+    exports p2;
 }
--- a/jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package p;
-
-public class Exported {
-
-    /**
-     * Public constructor
-     */
-    public Exported() { }
-
-    /**
-     * Public field
-     */
-    public static Object field;
-
-    /**
-     * Public method
-     */
-    public static void run() {
-    }
-}
--- a/jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package p;
-
-import java.lang.reflect.Module;
-
-public class Helper {
-    Helper() { }
-
-    public static void exportPackage(String pn, Module who) {
-        Helper.class.getModule().addExports(pn, who);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Helper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 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 p1;
+
+import java.lang.reflect.Module;
+
+/**
+ * Helper class in target module to allow test invoke addExports[Private]
+ */
+
+public class Helper {
+    Helper() { }
+
+    public static void addExports(String pn, Module who) {
+        Helper.class.getModule().addExports(pn, who);
+    }
+
+    public static void addOpens(String pn, Module who) {
+        Helper.class.getModule().addOpens(pn, who);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Public.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 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 p1;
+
+public class Public {
+
+    // public constructor
+    public Public() { }
+
+    // non-public constructor
+    private Public(Void ignore) { }
+
+    // public field
+    public static Object f1;
+
+    // non-public field
+    private static Object f2;
+
+    // public method
+    public static void foo() { }
+
+    // non-public method
+    private static void bar() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/p2/NonPublic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 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 p2;
+
+class NonPublic {
+
+    // public constructor
+    public NonPublic() { }
+
+    // non-public constructor
+    private NonPublic(Void ignore) { }
+
+    // public field
+    public static Object f1;
+
+    // non-public field
+    private static Object f2;
+
+    // public method
+    public static void foo() { }
+
+    // non-public method
+    private static void bar() { }
+}
--- a/jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package q;
-
-public class Internal {
-
-    /**
-     * Public constructor
-     */
-    public Internal() { }
-
-    /**
-     * Public field
-     */
-    public static Object field;
-
-    /**
-     * Public method
-     */
-    public static void run() {
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/q1/Public.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 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 q1;
+
+public class Public {
+
+    // public constructor
+    public Public() { }
+
+    // non-public constructor
+    private Public(Void ignore) { }
+
+    // public field
+    public static Object f1;
+
+    // non-public field
+    private static Object f2;
+
+    // public method
+    public static void foo() { }
+
+    // non-public method
+    private static void bar() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/q2/NonPublic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 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 q2;
+
+class NonPublic {
+
+    // public constructor
+    public NonPublic() { }
+
+    // non-public constructor
+    private NonPublic(Void ignore) { }
+
+    // public field
+    public static Object f1;
+
+    // non-public field
+    private static Object f2;
+
+    // public method
+    public static void foo() { }
+
+    // non-public method
+    private static void bar() { }
+}
--- a/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -23,166 +23,351 @@
 
 package test;
 
+import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
-import java.lang.reflect.InaccessibleObjectException;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Method;
 import java.lang.reflect.Module;
-import java.util.Optional;
 
 /**
- * Test access to public members in exported and non-exported packages.
+ * Test access to public/non-public members of public/non-public classes in
+ * exported and non-exported packages.
  */
 
 public class Main {
 
     public static void main(String[] args) throws Exception {
+        testPublicClassInExportedPackage();
+        testNonPublicClassInExportedPackage();
+        testPublicClassInNonExportedPackage();
+        testNonPublicClassInNonExportedPackage();
+    }
 
+    static void testPublicClassInExportedPackage() throws Exception {
         Module thisModule = Main.class.getModule();
-        assertTrue(thisModule.isNamed());
+        Module targetModule = getTargetModule();
+
+        assertTrue(targetModule.isExported("p1"));
+        assertTrue(targetModule.isExported("p1", thisModule));
+        assertTrue(targetModule.isExported("p1", targetModule));
+
+        assertFalse(targetModule.isOpen("p1"));
+        assertFalse(targetModule.isOpen("p1", thisModule));
+        assertTrue(targetModule.isOpen("p1", targetModule));
+
+        Class<?> clazz = Class.forName("p1.Public");
+        Constructor<?> ctor1 = clazz.getConstructor();   // public
+        Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class); // non-public
+
+        Field f1 = clazz.getField("f1");    // public
+        Field f2 = clazz.getDeclaredField("f2");    // non-public
+
+        Method m1 = clazz.getMethod("foo");  // public
+        Method m2 = clazz.getDeclaredMethod("bar");  // non-public
 
-        Optional<Module> om = Layer.boot().findModule("target");
-        assertTrue(om.isPresent());
+        tryAccessConstructor(ctor1, true);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, true);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, true);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, false);
+
+        targetAddOpens("p1", thisModule);
 
-        Module target = om.get();
+        tryAccessConstructor(ctor1, true);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, true);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, true);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, true);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, true);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, true);
+    }
+
+    static void testNonPublicClassInExportedPackage() throws Exception {
+        Module thisModule = Main.class.getModule();
+        Module targetModule = getTargetModule();
 
-        assertTrue(target.isExported("p"));
-        assertTrue(target.isExported("p", thisModule));
+        assertTrue(targetModule.isExported("p2"));
+        assertTrue(targetModule.isExported("p2", thisModule));
+        assertTrue(targetModule.isExported("p2", targetModule));
+
+        assertFalse(targetModule.isOpen("p2"));
+        assertFalse(targetModule.isOpen("p2", thisModule));
+        assertTrue(targetModule.isOpen("p1", targetModule));
+
+        Class<?> clazz = Class.forName("p2.NonPublic");
+        Constructor<?> ctor1 = clazz.getConstructor();
+        Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class);
+
+        Field f1 = clazz.getField("f1");    // public
+        Field f2 = clazz.getDeclaredField("f2");    // non-public
+
+        Method m1 = clazz.getMethod("foo");  // public
+        Method m2 = clazz.getDeclaredMethod("bar");  // non-public
+
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
+
+        targetAddExports("p2", thisModule);
 
-        assertFalse(target.isExported("q"));
-        assertFalse(target.isExported("q", thisModule));
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
 
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
+
+        targetAddOpens("p2", thisModule);
 
-        // thisModule does not read the target module
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
 
-        assertFalse(thisModule.canRead(target));
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, true);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, true);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, true);
+    }
+
+    static void testPublicClassInNonExportedPackage() throws Exception {
+        Module thisModule = Main.class.getModule();
+        Module targetModule = getTargetModule();
 
-        tryAccessPublicMembers("p.Exported", true);
-        tryAccessPublicMembers("q.Internal", false);
+        assertFalse(targetModule.isExported("q1"));
+        assertFalse(targetModule.isExported("q1", thisModule));
+        assertTrue(targetModule.isExported("q1", targetModule));
+
+        assertFalse(targetModule.isOpen("q1"));
+        assertFalse(targetModule.isOpen("q1", thisModule));
+        assertTrue(targetModule.isOpen("q1", targetModule));
+
+        Class<?> clazz = Class.forName("q1.Public");
+        Constructor<?> ctor1 = clazz.getConstructor();  // public
+        Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class);  // non-public
+
+        Field f1 = clazz.getField("f1");    // public
+        Field f2 = clazz.getDeclaredField("f2");    // non-public
 
+        Method m1 = clazz.getMethod("foo");  // public
+        Method m2 = clazz.getDeclaredMethod("bar");  // non-public
 
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
 
-        // thisModule reads the target module
+        targetAddExports("q1", thisModule);
+
+        tryAccessConstructor(ctor1, true);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, true);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, true);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, false);
 
-        thisModule.addReads(target);
-        assertTrue(thisModule.canRead(target));
+        targetAddOpens("q1", thisModule);
+
+        tryAccessConstructor(ctor1, true);
+        tryAccessConstructor(ctor1, false);
+        tryAccessMethod(m1, true);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, true);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, true);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, true);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, true);
+    }
 
-        tryAccessPublicMembers("p.Exported", true);
-        tryAccessPublicMembers("q.Internal", false);
+    static void testNonPublicClassInNonExportedPackage() throws Exception {
+        Module thisModule = Main.class.getModule();
+        Module targetModule = getTargetModule();
+
+        assertFalse(targetModule.isExported("q2"));
+        assertFalse(targetModule.isExported("q2", thisModule));
+        assertTrue(targetModule.isExported("q2", targetModule));
+
+        assertFalse(targetModule.isOpen("q2"));
+        assertFalse(targetModule.isOpen("q2", thisModule));
+        assertTrue(targetModule.isOpen("q2", targetModule));
 
+        Class<?> clazz = Class.forName("q2.NonPublic");
+        Constructor<?> ctor1 = clazz.getConstructor();  // public
+        Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class);  // non-public
 
+        Field f1 = clazz.getField("f1");    // public
+        Field f2 = clazz.getDeclaredField("f2");    // non-public
 
-        // change target module to export its internal package to thisModule
+        Method m1 = clazz.getMethod("foo");  // public
+        Method m2 = clazz.getDeclaredMethod("bar");  // non-public
+
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
 
-        targetAddExports("q", thisModule);
-        assertFalse(target.isExported("q"));
-        assertTrue(target.isExported("q", thisModule));
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
+
+        targetAddExports("q2", thisModule);
+
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
 
-        tryAccessPublicMembers("p.Exported", true);
-        tryAccessPublicMembers("q.Internal", true);
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
+
+        targetAddOpens("q2", thisModule);
+
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, true);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, true);
     }
 
 
-    /**
-     * Attempt to access public members in a target class.
-     */
-    static void tryAccessPublicMembers(String cn, boolean shouldSucceed)
-        throws Exception
-    {
-
-        Class<?> clazz = Class.forName(cn);
-
-        Module thisModule = Main.class.getModule();
-        Module targetModule = clazz.getModule();
+    static Module getTargetModule() {
+        return Layer.boot().findModule("target").get();
+    }
 
-        // check if the target class is in an exported package
-        String pn = cn.substring(0, cn.lastIndexOf('.'));
-        boolean exported = targetModule.isExported(pn, thisModule);
-        assertTrue(exported == shouldSucceed);
-        boolean shouldFail = !shouldSucceed;
-
-
-        // Class.newInstance
-
-        try {
-            clazz.newInstance();
-            assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
-        }
-
-
-        // Constructor.newInstance and Constructor.setAccessible
-
-        Constructor<?> ctor = clazz.getConstructor();
+    static void tryAccessConstructor(Constructor<?> ctor, boolean shouldSucceed) {
         try {
             ctor.newInstance();
             assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            assertFalse(shouldSucceed);
         }
-        try {
-            ctor.setAccessible(true);
-            assertTrue(shouldSucceed);
-            ctor.newInstance();
-        } catch (InaccessibleObjectException e) {
-            assertTrue(shouldFail);
-        }
+    }
 
-
-        // Method.invoke and Method.setAccessible
-
-        Method m = clazz.getDeclaredMethod("run");
+    static void tryAccessMethod(Method method, boolean shouldSucceed) {
         try {
-            m.invoke(null);
-            assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
-        }
-        try {
-            m.setAccessible(true);
+            method.invoke(null);
             assertTrue(shouldSucceed);
-            m.invoke(null);
-        } catch (InaccessibleObjectException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            e.printStackTrace();
+            assertFalse(shouldSucceed);
         }
+    }
 
-        // Field.get, Field.set and Field.setAccessible
-
-        Field f = clazz.getDeclaredField("field");
+    static void tryAccessObjectField(Field f, boolean shouldSucceed) {
         try {
             f.get(null);
             assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            assertFalse(shouldSucceed);
         }
         try {
-            f.set(null, 100);
+            f.set(null, new Object());
             assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            assertFalse(shouldSucceed);
         }
+    }
+
+    static void trySetAccessible(AccessibleObject ao, boolean shouldSucceed) {
         try {
-            f.setAccessible(true);
-            f.get(null);
-            f.set(null, 100);
+            ao.setAccessible(true);
             assertTrue(shouldSucceed);
-        } catch (InaccessibleObjectException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            assertFalse(shouldSucceed);
         }
-
     }
 
     /**
      * Update target module to export a package to the given module.
      */
     static void targetAddExports(String pn, Module who) throws Exception {
-        Class<?> helper = Class.forName("p.Helper");
-        Method m = helper.getMethod("exportPackage", String.class, Module.class);
+        Class<?> helper = Class.forName("p1.Helper");
+        Method m = helper.getMethod("addExports", String.class, Module.class);
         m.invoke(null, pn, who);
     }
 
+    /**
+     * Update target module to open a package to the given module.
+     */
+    static void targetAddOpens(String pn, Module who) throws Exception {
+        Class<?> helper = Class.forName("p1.Helper");
+        Method m = helper.getMethod("addOpens", String.class, Module.class);
+        m.invoke(null, pn, who);
+    }
 
     static void assertTrue(boolean expr) {
         if (!expr) throw new RuntimeException();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/Basic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,77 @@
+/*
+ * 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
+ * @library src
+ * @build m/* Basic
+ * @run testng/othervm Basic
+ * @summary Basic test for annotations on modules
+ */
+
+import java.lang.reflect.Module;
+import java.util.Arrays;
+
+import p.annotation.Foo;
+import p.annotation.Bar;
+import p.annotation.Baz;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class Basic {
+
+    final Module module = Foo.class.getModule();
+
+    /**
+     * {@code @Foo} does not have RUNTIME retention policy.
+     */
+    @Test
+    public void testInvisibleAnnotation() {
+        assertFalse(module.isAnnotationPresent(Foo.class));
+        assertNull(module.getAnnotation(Foo.class));
+    }
+
+    /**
+     * {@code @Bar} has RUNTIME retention policy and value "bar"
+     */
+    @Test
+    public void testBarAnnotation() {
+        assertTrue(module.isAnnotationPresent(Bar.class));
+        Bar bar = module.getAnnotation(Bar.class);
+        assertNotNull(bar);
+        assertEquals(bar.value(), "bar");
+    }
+
+    /**
+     * {@code @Baz} has RUNTIME retention policy has a repeating value
+     */
+    @Test
+    public void testBazAnnotation() {
+        assertTrue(module.isAnnotationPresent(Baz.class));
+        Baz baz = module.getAnnotation(Baz.class);
+        assertNotNull(baz);
+        String[] expected = { "one", "two", "three" };
+        assertTrue(Arrays.equals(baz.value(), expected));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+import p.annotation.*;
+
+@Foo
+@Bar("bar")
+@Baz({"one", "two", "three"})
+module m {
+    exports p.annotation;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Bar.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 p.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.MODULE;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value={MODULE})
+public @interface Bar {
+   String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Baz.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 p.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.MODULE;
+
+@Target(value={MODULE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Baz {
+   String[] value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Foo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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 p.annotation;
+
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.MODULE;
+
+@Target(value={MODULE})
+public @interface Foo {}
--- a/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,6 +22,6 @@
  */
 
 module m3 {
-    requires public m2;
+    requires transitive m2;
     exports p.three;
 }
--- a/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,7 +23,7 @@
 
 module test {
     requires m1;
-    requires m3;   // requires public m2
+    requires m3;   // requires transitive m2
 
     exports jdk.test;
 }
--- a/jdk/test/java/net/Authenticator/B4933582.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/net/Authenticator/B4933582.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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
@@ -21,6 +21,15 @@
  * questions.
  */
 
+/*
+ * @test
+ * @bug 4933582
+ * @library ../../../sun/net/www/httptest
+ * @modules java.base/sun.net.www
+ *          java.base/sun.net.www.protocol.http
+ * @build HttpCallback HttpTransaction TestHttpServer B4933582
+ * @run main/othervm B4933582
+ */
 import java.io.*;
 import java.net.*;
 import java.util.*;
@@ -44,7 +53,7 @@
         req.orderlyClose();
     }
 
-    static boolean firstTime = true;
+    static volatile boolean firstTime = true;
 
     public void request (HttpTransaction req) {
         try {
@@ -114,43 +123,67 @@
         URL url = new URL (u);
         System.out.println ("client opening connection to: " + u);
         URLConnection urlc = url.openConnection ();
-        InputStream is = urlc.getInputStream ();
-        read (is);
-        is.close();
+        try(InputStream is = urlc.getInputStream ()) {
+            read (is);
+        }
     }
 
     static TestHttpServer server;
 
     public static void main (String[] args) throws Exception {
-        firstTime = args[0].equals ("first");
         MyAuthenticator auth = new MyAuthenticator ();
         Authenticator.setDefault (auth);
         CacheImpl cache;
         try {
-            if (firstTime) {
-                server = new TestHttpServer (new B4933582(), 1, 10, 0);
-                cache = new CacheImpl (server.getLocalPort());
-            } else {
-                cache = new CacheImpl ();
-                server = new TestHttpServer(new B4933582(), 1, 10, cache.getPort());
-            }
+            server = new TestHttpServer (new B4933582(), 1, 10, 0);
+            cache = new CacheImpl (server.getLocalPort());
             AuthCacheValue.setAuthCache (cache);
-            System.out.println ("Server: listening on port: " + server.getLocalPort());
             client ("http://localhost:"+server.getLocalPort()+"/d1/foo.html");
-        } catch (Exception e) {
+        } finally {
             if (server != null) {
                 server.terminate();
             }
-            throw e;
         }
+
         int f = auth.getCount();
-        if (firstTime && f != 1) {
-            except ("Authenticator was called "+f+" times. Should be 1");
+        if (f != 1) {
+            except("Authenticator was called " + f + " times. Should be 1");
         }
-        if (!firstTime && f != 0) {
-            except ("Authenticator was called "+f+" times. Should be 0");
+
+        firstTime = false;
+
+        int retries = 0;
+        cache = new CacheImpl();
+        while (true) {
+            try {
+                server = new TestHttpServer(new B4933582(), 1, 10,
+                        cache.getPort());
+                break;
+            } catch (BindException e) {
+                if (retries++ < 5) {
+                    Thread.sleep(200L);
+                    System.out.println("BindException \"" + e.getMessage()
+                            + "\", retrying...");
+                    continue;
+                } else {
+                    throw e;
+                }
+            }
         }
-        server.terminate();
+
+        try {
+            AuthCacheValue.setAuthCache(cache);
+            client("http://localhost:" + server.getLocalPort() + "/d1/foo.html");
+        } finally {
+            if (server != null) {
+                server.terminate();
+            }
+        }
+
+        f = auth.getCount();
+        if (f != 1) {
+            except("Authenticator was called " + f + " times. Should be 1");
+        }
     }
 
     public static void except (String s) {
@@ -163,7 +196,7 @@
             super ();
         }
 
-        int count = 0;
+        volatile int count = 0;
 
         public PasswordAuthentication getPasswordAuthentication () {
             PasswordAuthentication pw;
@@ -178,7 +211,7 @@
     }
 
     static class CacheImpl extends AuthCacheImpl {
-        HashMap map;
+        HashMap<String,LinkedList<AuthCacheValue>> map;
         int port; // need to store the port number the server is using
 
         CacheImpl () throws IOException {
@@ -190,20 +223,18 @@
             this.port = port;
             File src = new File ("cache.ser");
             if (src.exists()) {
-                ObjectInputStream is = new ObjectInputStream (
-                    new FileInputStream (src)
-                );
-                try {
-                    map = (HashMap)is.readObject ();
+                try (ObjectInputStream is = new ObjectInputStream(
+                        new FileInputStream(src))) {
+                    map = (HashMap<String,LinkedList<AuthCacheValue>>)is
+                              .readObject();
                     this.port = (Integer)is.readObject ();
                     System.out.println ("read port from file " + port);
                 } catch (ClassNotFoundException e) {
                     assert false;
                 }
-                is.close();
                 System.out.println ("setMap from cache.ser");
             } else {
-                map = new HashMap();
+                map = new HashMap<>();
             }
             setMap (map);
         }
@@ -213,20 +244,22 @@
         }
 
         private void writeMap () {
+            File dst = new File("cache.ser");
             try {
-                File dst = new File ("cache.ser");
                 dst.delete();
                 if (!dst.createNewFile()) {
                     return;
                 }
-                ObjectOutputStream os = new ObjectOutputStream (
-                        new FileOutputStream (dst)
-                );
+            } catch (IOException e) {
+            }
+
+            try (ObjectOutputStream os = new ObjectOutputStream(
+                    new FileOutputStream(dst))) {
                 os.writeObject(map);
                 os.writeObject(port);
-                System.out.println ("wrote port " + port);
-                os.close();
-            } catch (IOException e) {}
+                System.out.println("wrote port " + port);
+            } catch (IOException e) {
+            }
         }
 
         public void put (String pkey, AuthCacheValue value) {
--- a/jdk/test/java/net/Authenticator/B4933582.sh	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-#
-# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please 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 4933582
-
-OS=`uname -s`
-case "$OS" in
-  SunOS | Linux | Darwin | AIX )
-    PS=":"
-    FS="/"
-    ;;
-  CYGWIN* )
-    PS=";"
-    FS="/"
-    ;;
-  Windows* )
-    PS=";"
-    FS="\\"
-    ;;
-  * )
-    echo "Unrecognized system!"
-    exit 1;
-    ;;
-esac
-
-EXTRAOPTS="--add-exports java.base/sun.net.www=ALL-UNNAMED --add-exports java.base/sun.net.www.protocol.http=ALL-UNNAMED"
-export EXTRAOPTS
-
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . \
-    -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest" ${TESTSRC}${FS}B4933582.java
-rm -f cache.ser auth.save
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 first
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 second
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/HttpURLConnection/SetAuthenticator/HTTPSetAuthenticatorTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.Authenticator;
+import java.net.HttpURLConnection;
+import java.net.Proxy;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @test
+ * @bug 8169415
+ * @library /lib/testlibrary/
+ * @modules java.base/sun.net.www
+ *          java.base/sun.net.www.protocol.http
+ *          jdk.httpserver/sun.net.httpserver
+ * @build jdk.testlibrary.SimpleSSLContext HTTPTest HTTPTestServer HTTPTestClient HTTPSetAuthenticatorTest
+ * @summary A simple HTTP test that starts an echo server supporting the given
+ *          authentication scheme, then starts a regular HTTP client to invoke it.
+ *          The client first does a GET request on "/", then follows on
+ *          with a POST request that sends "Hello World!" to the server.
+ *          The client expects to receive "Hello World!" in return.
+ *          The test supports several execution modes:
+ *            SERVER: The server performs Server authentication;
+ *            PROXY:  The server pretends to be a proxy and performs
+ *                    Proxy authentication;
+ *            SERVER307: The server redirects the client (307) to another
+ *                    server that perform Server authentication;
+ *            PROXY305: The server attempts to redirect
+ *                    the client to a proxy using 305 code;
+ *           This test runs the client several times, providing different
+ *           authenticators to the HttpURLConnection and verifies that
+ *           the authenticator is invoked as expected - validating that
+ *           connections with different authenticators do not share each
+ *           other's socket channel and authentication info.
+ *           Note: BASICSERVER means that the server will let the underlying
+ *                 com.sun.net.httpserver.HttpServer perform BASIC
+ *                 authentication when in Server mode. There should be
+ *                 no real difference between BASICSERVER and BASIC - it should
+ *                 be transparent on the client side.
+ * @run main/othervm HTTPSetAuthenticatorTest NONE SERVER PROXY SERVER307 PROXY305
+ * @run main/othervm HTTPSetAuthenticatorTest DIGEST SERVER
+ * @run main/othervm HTTPSetAuthenticatorTest DIGEST PROXY
+ * @run main/othervm HTTPSetAuthenticatorTest DIGEST PROXY305
+ * @run main/othervm HTTPSetAuthenticatorTest DIGEST SERVER307
+ * @run main/othervm HTTPSetAuthenticatorTest BASIC  SERVER
+ * @run main/othervm HTTPSetAuthenticatorTest BASIC  PROXY
+ * @run main/othervm HTTPSetAuthenticatorTest BASIC  PROXY305
+ * @run main/othervm HTTPSetAuthenticatorTest BASIC  SERVER307
+ * @run main/othervm HTTPSetAuthenticatorTest BASICSERVER SERVER
+ * @run main/othervm HTTPSetAuthenticatorTest BASICSERVER SERVER307
+ *
+ * @author danielfuchs
+ */
+public class HTTPSetAuthenticatorTest extends HTTPTest {
+
+    public static void main(String[] args) throws Exception {
+        String[] schemes;
+        String[] params;
+         if (args == null || args.length == 0) {
+            schemes = Stream.of(HttpSchemeType.values())
+                        .map(HttpSchemeType::name)
+                        .collect(Collectors.toList())
+                        .toArray(new String[0]);
+            params = new String[0];
+        } else {
+            schemes = new String[] { args[0] };
+            params = Arrays.copyOfRange(args, 1, args.length);
+        }
+        for (String scheme : schemes) {
+            System.out.println("==== Testing with scheme=" + scheme + " ====\n");
+            new HTTPSetAuthenticatorTest(HttpSchemeType.valueOf(scheme))
+                .execute(params);
+            System.out.println();
+        }
+    }
+
+    final HttpSchemeType scheme;
+    public HTTPSetAuthenticatorTest(HttpSchemeType scheme) {
+        this.scheme = scheme;
+    }
+
+    @Override
+    public HttpSchemeType getHttpSchemeType() {
+        return scheme;
+    }
+
+    @Override
+    public int run(HTTPTestServer server,
+                   HttpProtocolType protocol,
+                   HttpAuthType mode)
+            throws IOException
+    {
+        HttpTestAuthenticator authOne = new HttpTestAuthenticator("dublin", "foox");
+        HttpTestAuthenticator authTwo = new HttpTestAuthenticator("dublin", "foox");
+        int expectedIncrement = scheme == HttpSchemeType.NONE
+                                ? 0 : EXPECTED_AUTH_CALLS_PER_TEST;
+        int count;
+        int defaultCount = AUTHENTICATOR.count.get();
+
+        // Connect to the server with a GET request, then with a
+        // POST that contains "Hello World!"
+        // Uses authenticator #1
+        System.out.println("\nClient: Using authenticator #1: "
+            + toString(authOne));
+        HTTPTestClient.connect(protocol, server, mode, authOne);
+        count = authOne.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #1 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+
+        // Connect to the server with a GET request, then with a
+        // POST that contains "Hello World!"
+        // Uses authenticator #2
+        System.out.println("\nClient: Using authenticator #2: "
+            + toString(authTwo));
+        HTTPTestClient.connect(protocol, server, mode, authTwo);
+        count = authTwo.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #2 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+        count = authTwo.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #2 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+
+        // Connect to the server with a GET request, then with a
+        // POST that contains "Hello World!"
+        // Uses authenticator #1
+        System.out.println("\nClient: Using authenticator #1 again: "
+            + toString(authOne));
+        HTTPTestClient.connect(protocol, server, mode, authOne);
+        count = authOne.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #1 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+        count = authTwo.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #2 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+        count =  AUTHENTICATOR.count.get();
+        if (count != defaultCount) {
+            throw new AssertionError("Default Authenticator called " + count(count)
+                + " expected it to be called " + expected(defaultCount));
+        }
+
+        // Now tries with the default authenticator: it should be invoked.
+        System.out.println("\nClient: Using the default authenticator: "
+            + toString(null));
+        HTTPTestClient.connect(protocol, server, mode, null);
+        count = authOne.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #1 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+        count = authTwo.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #2 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+        count =  AUTHENTICATOR.count.get();
+        if (count != defaultCount + expectedIncrement) {
+            throw new AssertionError("Default Authenticator called " + count(count)
+                + " expected it to be called " + expected(defaultCount + expectedIncrement));
+        }
+
+        // Now tries with explicitly setting the default authenticator: it should
+        // be invoked again.
+        // Uncomment the code below when 8169068 is available.
+//        System.out.println("\nClient: Explicitly setting the default authenticator: "
+//            + toString(Authenticator.getDefault()));
+//        HTTPTestClient.connect(protocol, server, mode, Authenticator.getDefault());
+//        count = authOne.count.get();
+//        if (count != expectedIncrement) {
+//            throw new AssertionError("Authenticator #1 called " + count(count)
+//                + " expected it to be called " + expected(expectedIncrement));
+//        }
+//        count = authTwo.count.get();
+//        if (count != expectedIncrement) {
+//            throw new AssertionError("Authenticator #2 called " + count(count)
+//                + " expected it to be called " + expected(expectedIncrement));
+//        }
+//        count =  AUTHENTICATOR.count.get();
+//        if (count != defaultCount + 2 * expectedIncrement) {
+//            throw new AssertionError("Default Authenticator called " + count(count)
+//                + " expected it to be called "
+//                + expected(defaultCount + 2 * expectedIncrement));
+//        }
+
+        // Now tries to set an authenticator on a connected connection.
+        URL url = url(protocol,  server.getAddress(), "/");
+        Proxy proxy = proxy(server, mode);
+        HttpURLConnection conn = openConnection(url, mode, proxy);
+        try {
+            conn.setAuthenticator(null);
+            throw new RuntimeException("Expected NullPointerException"
+                    + " trying to set a null authenticator"
+                    + " not raised.");
+        } catch (NullPointerException npe) {
+            System.out.println("Client: caught expected NPE"
+                    + " trying to set a null authenticator: "
+                    + npe);
+        }
+        conn.connect();
+        try {
+            try {
+                conn.setAuthenticator(authOne);
+                throw new RuntimeException("Expected IllegalStateException"
+                        + " trying to set an authenticator after connect"
+                        + " not raised.");
+            } catch (IllegalStateException ise) {
+                System.out.println("Client: caught expected ISE"
+                        + " trying to set an authenticator after connect: "
+                        + ise);
+            }
+            // Uncomment the code below when 8169068 is available.
+//            try {
+//                conn.setAuthenticator(Authenticator.getDefault());
+//                throw new RuntimeException("Expected IllegalStateException"
+//                        + " trying to set an authenticator after connect"
+//                        + " not raised.");
+//            } catch (IllegalStateException ise) {
+//                System.out.println("Client: caught expected ISE"
+//                        + " trying to set an authenticator after connect: "
+//                        + ise);
+//            }
+            try {
+                conn.setAuthenticator(null);
+                throw new RuntimeException("Expected"
+                        + " IllegalStateException or NullPointerException"
+                        + " trying to set a null authenticator after connect"
+                        + " not raised.");
+            } catch (IllegalStateException | NullPointerException xxe) {
+                System.out.println("Client: caught expected "
+                        + xxe.getClass().getSimpleName()
+                        + " trying to set a null authenticator after connect: "
+                        + xxe);
+            }
+        } finally {
+            conn.disconnect();
+        }
+
+        // double check that authOne and authTwo haven't been invoked.
+        count = authOne.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #1 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+        count = authTwo.count.get();
+        if (count != expectedIncrement) {
+            throw new AssertionError("Authenticator #2 called " + count(count)
+                + " expected it to be called " + expected(expectedIncrement));
+        }
+
+        // All good!
+        // return the number of times the default authenticator is supposed
+        // to have been called.
+        return scheme == HttpSchemeType.NONE ? 0 : 1 * EXPECTED_AUTH_CALLS_PER_TEST;
+    }
+
+    static String toString(Authenticator a) {
+        return sun.net.www.protocol.http.AuthenticatorKeys.getKey(a);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/HttpURLConnection/SetAuthenticator/HTTPTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,283 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.Authenticator;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.PasswordAuthentication;
+import java.net.Proxy;
+import java.net.URL;
+import java.util.Locale;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Stream;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import jdk.testlibrary.SimpleSSLContext;
+
+/**
+ * @test
+ * @bug 8169415
+ * @library /lib/testlibrary/
+ * @modules java.base/sun.net.www
+ *          jdk.httpserver/sun.net.httpserver
+ * @build jdk.testlibrary.SimpleSSLContext HTTPTest HTTPTestServer HTTPTestClient
+ * @summary A simple HTTP test that starts an echo server supporting Digest
+ *          authentication, then starts a regular HTTP client to invoke it.
+ *          The client first does a GET request on "/", then follows on
+ *          with a POST request that sends "Hello World!" to the server.
+ *          The client expects to receive "Hello World!" in return.
+ *          The test supports several execution modes:
+ *            SERVER: The server performs Digest Server authentication;
+ *            PROXY:  The server pretends to be a proxy and performs
+ *                    Digest Proxy authentication;
+ *            SERVER307: The server redirects the client (307) to another
+ *                    server that perform Digest authentication;
+ *            PROXY305: The server attempts to redirect
+ *                    the client to a proxy using 305 code;
+ * @run main/othervm HTTPTest SERVER
+ * @run main/othervm HTTPTest PROXY
+ * @run main/othervm HTTPTest SERVER307
+ * @run main/othervm HTTPTest PROXY305
+ *
+ * @author danielfuchs
+ */
+public class HTTPTest {
+
+    public static final boolean DEBUG =
+         Boolean.parseBoolean(System.getProperty("test.debug", "false"));
+    public static enum HttpAuthType { SERVER, PROXY, SERVER307, PROXY305 };
+    public static enum HttpProtocolType { HTTP, HTTPS };
+    public static enum HttpSchemeType { NONE, BASICSERVER, BASIC, DIGEST };
+    public static final HttpAuthType DEFAULT_HTTP_AUTH_TYPE = HttpAuthType.SERVER;
+    public static final HttpProtocolType DEFAULT_PROTOCOL_TYPE = HttpProtocolType.HTTP;
+    public static final HttpSchemeType DEFAULT_SCHEME_TYPE = HttpSchemeType.DIGEST;
+
+    public static class HttpTestAuthenticator extends Authenticator {
+        private final String realm;
+        private final String username;
+        // Used to prevent incrementation of 'count' when calling the
+        // authenticator from the server side.
+        private final ThreadLocal<Boolean> skipCount = new ThreadLocal<>();
+        // count will be incremented every time getPasswordAuthentication()
+        // is called from the client side.
+        final AtomicInteger count = new AtomicInteger();
+
+        public HttpTestAuthenticator(String realm, String username) {
+            this.realm = realm;
+            this.username = username;
+        }
+
+        @Override
+        protected PasswordAuthentication getPasswordAuthentication() {
+            if (skipCount.get() == null || skipCount.get().booleanValue() == false) {
+                System.out.println("Authenticator called: " + count.incrementAndGet());
+            }
+            return new PasswordAuthentication(getUserName(),
+                    new char[] {'b','a','r'});
+        }
+
+        // Called by the server side to get the password of the user
+        // being authentified.
+        public final char[] getPassword(String user) {
+            if (user.equals(username)) {
+                skipCount.set(Boolean.TRUE);
+                try {
+                    return getPasswordAuthentication().getPassword();
+                } finally {
+                    skipCount.set(Boolean.FALSE);
+                }
+            }
+            throw new SecurityException("User unknown: " + user);
+        }
+
+        public final String getUserName() {
+            return username;
+        }
+        public final String getRealm() {
+            return realm;
+        }
+
+    }
+    public static final HttpTestAuthenticator AUTHENTICATOR;
+    static {
+        AUTHENTICATOR = new HttpTestAuthenticator("dublin", "foox");
+        Authenticator.setDefault(AUTHENTICATOR);
+    }
+
+    static {
+        try {
+            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
+                public boolean verify(String hostname, SSLSession session) {
+                    return true;
+                }
+            });
+            SSLContext.setDefault(new SimpleSSLContext().get());
+        } catch (IOException ex) {
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    static final Logger logger = Logger.getLogger ("com.sun.net.httpserver");
+    static {
+        if (DEBUG) logger.setLevel(Level.ALL);
+        Stream.of(Logger.getLogger("").getHandlers())
+              .forEach(h -> h.setLevel(Level.ALL));
+    }
+
+    static final int EXPECTED_AUTH_CALLS_PER_TEST = 1;
+
+    public static void main(String[] args) throws Exception {
+        // new HTTPTest().execute(HttpAuthType.SERVER.name());
+        new HTTPTest().execute(args);
+    }
+
+    public void execute(String... args) throws Exception {
+        Stream<HttpAuthType> modes;
+        if (args == null || args.length == 0) {
+            modes = Stream.of(HttpAuthType.values());
+        } else {
+            modes = Stream.of(args).map(HttpAuthType::valueOf);
+        }
+        modes.forEach(this::test);
+        System.out.println("Test PASSED - Authenticator called: "
+                 + expected(AUTHENTICATOR.count.get()));
+    }
+
+    public void test(HttpAuthType mode) {
+        for (HttpProtocolType type: HttpProtocolType.values()) {
+            test(type, mode);
+        }
+    }
+
+    public HttpSchemeType getHttpSchemeType() {
+        return DEFAULT_SCHEME_TYPE;
+    }
+
+    public void test(HttpProtocolType protocol, HttpAuthType mode) {
+        if (mode == HttpAuthType.PROXY305 && protocol == HttpProtocolType.HTTPS ) {
+            // silently skip unsupported test combination
+            return;
+        }
+        System.out.println("\n**** Testing " + protocol + " "
+                           + mode + " mode ****\n");
+        int authCount = AUTHENTICATOR.count.get();
+        int expectedIncrement = 0;
+        try {
+            // Creates an HTTP server that echoes back whatever is in the
+            // request body.
+            HTTPTestServer server =
+                    HTTPTestServer.create(protocol,
+                                          mode,
+                                          AUTHENTICATOR,
+                                          getHttpSchemeType());
+            try {
+                expectedIncrement += run(server, protocol, mode);
+            } finally {
+                server.stop();
+            }
+        }  catch (IOException ex) {
+            ex.printStackTrace(System.err);
+            throw new UncheckedIOException(ex);
+        }
+        int count = AUTHENTICATOR.count.get();
+        if (count != authCount + expectedIncrement) {
+            throw new AssertionError("Authenticator called " + count(count)
+                        + " expected it to be called "
+                        + expected(authCount + expectedIncrement));
+        }
+    }
+
+    /**
+     * Runs the test with the given parameters.
+     * @param server    The server
+     * @param protocol  The protocol (HTTP/HTTPS)
+     * @param mode      The mode (PROXY, SERVER, SERVER307...)
+     * @return The number of times the default authenticator should have been
+     *         called.
+     * @throws IOException in case of connection or protocol issues
+     */
+    public int run(HTTPTestServer server,
+                   HttpProtocolType protocol,
+                   HttpAuthType mode)
+            throws IOException
+    {
+        // Connect to the server with a GET request, then with a
+        // POST that contains "Hello World!"
+        HTTPTestClient.connect(protocol, server, mode, null);
+        // return the number of times the default authenticator is supposed
+        // to have been called.
+        return EXPECTED_AUTH_CALLS_PER_TEST;
+    }
+
+    public static String count(int count) {
+        switch(count) {
+            case 0: return "not even once";
+            case 1: return "once";
+            case 2: return "twice";
+            default: return String.valueOf(count) + " times";
+        }
+    }
+
+    public static String expected(int count) {
+        switch(count) {
+            default: return count(count);
+        }
+    }
+    public static String protocol(HttpProtocolType type) {
+        return type.name().toLowerCase(Locale.US);
+    }
+
+    public static URL url(HttpProtocolType protocol, InetSocketAddress address,
+                          String path) throws MalformedURLException {
+        return new URL(protocol(protocol),
+                       address.getHostString(),
+                       address.getPort(), path);
+    }
+
+    public static Proxy proxy(HTTPTestServer server, HttpAuthType authType) {
+        return (authType == HttpAuthType.PROXY)
+               ? new Proxy(Proxy.Type.HTTP, server.getAddress())
+               : null;
+    }
+
+    public static HttpURLConnection openConnection(URL url,
+                                                   HttpAuthType authType,
+                                                   Proxy proxy)
+                                    throws IOException {
+
+        HttpURLConnection conn = (HttpURLConnection)
+                (authType == HttpAuthType.PROXY
+                    ? url.openConnection(proxy)
+                    : url.openConnection());
+        return conn;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/HttpURLConnection/SetAuthenticator/HTTPTestClient.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.Authenticator;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URL;
+import javax.net.ssl.HttpsURLConnection;
+
+/**
+ * A simple Http client that connects to the HTTPTestServer.
+ * @author danielfuchs
+ */
+public class HTTPTestClient extends HTTPTest {
+
+    public static void connect(HttpProtocolType protocol,
+                               HTTPTestServer server,
+                               HttpAuthType authType,
+                               Authenticator auth)
+            throws IOException {
+
+        InetSocketAddress address = server.getAddress();
+        final URL url = url(protocol,  address, "/");
+        final Proxy proxy = proxy(server, authType);
+
+        System.out.println("Client: FIRST request: " + url + " GET");
+        HttpURLConnection conn = openConnection(url, authType, proxy);
+        configure(conn, auth);
+        System.out.println("Response code: " + conn.getResponseCode());
+        String result = new String(conn.getInputStream().readAllBytes(), "UTF-8");
+        System.out.println("Response body: " + result);
+        if (!result.isEmpty()) {
+            throw new RuntimeException("Unexpected response to GET: " + result);
+        }
+        System.out.println("\nClient: NEXT request: " + url + " POST");
+        conn = openConnection(url, authType, proxy);
+        configure(conn, auth);
+        conn.setRequestMethod("POST");
+        conn.setDoOutput(true);
+        conn.setDoInput(true);
+        conn.getOutputStream().write("Hello World!".getBytes("UTF-8"));
+        System.out.println("Response code: " + conn.getResponseCode());
+        result = new String(conn.getInputStream().readAllBytes(), "UTF-8");
+        System.out.println("Response body: " + result);
+        if ("Hello World!".equals(result)) {
+            System.out.println("Test passed!");
+        } else {
+            throw new RuntimeException("Unexpected response to POST: " + result);
+        }
+    }
+
+    private static void configure(HttpURLConnection conn, Authenticator auth)
+        throws IOException {
+        if (auth != null) {
+            conn.setAuthenticator(auth);
+        }
+        if (conn instanceof HttpsURLConnection) {
+            System.out.println("Client: configuring SSL connection");
+            // We have set a default SSLContext so we don't need to do
+            // anything here. Otherwise it could look like:
+            //     HttpsURLConnection httpsConn = (HttpsURLConnection)conn;
+            //     httpsConn.setSSLSocketFactory(
+            //               new SimpleSSLContext().get().getSocketFactory());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/HttpURLConnection/SetAuthenticator/HTTPTestServer.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,995 @@
+/*
+ * 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.
+ */
+
+import com.sun.net.httpserver.BasicAuthenticator;
+import com.sun.net.httpserver.Filter;
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsParameters;
+import com.sun.net.httpserver.HttpsServer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+import java.util.stream.Collectors;
+import javax.net.ssl.SSLContext;
+import sun.net.www.HeaderParser;
+
+/**
+ * A simple HTTP server that supports Digest authentication.
+ * By default this server will echo back whatever is present
+ * in the request body.
+ * @author danielfuchs
+ */
+public class HTTPTestServer extends HTTPTest {
+
+    final HttpServer      serverImpl; // this server endpoint
+    final HTTPTestServer  redirect;   // the target server where to redirect 3xx
+    final HttpHandler     delegate;   // unused
+
+    private HTTPTestServer(HttpServer server, HTTPTestServer target,
+                           HttpHandler delegate) {
+        this.serverImpl = server;
+        this.redirect = target;
+        this.delegate = delegate;
+    }
+
+    public static void main(String[] args)
+            throws IOException {
+
+           HTTPTestServer server = create(HTTPTest.DEFAULT_PROTOCOL_TYPE,
+                                          HTTPTest.DEFAULT_HTTP_AUTH_TYPE,
+                                          HTTPTest.AUTHENTICATOR,
+                                          HTTPTest.DEFAULT_SCHEME_TYPE);
+           try {
+               System.out.println("Server created at " + server.getAddress());
+               System.out.println("Strike <Return> to exit");
+               System.in.read();
+           } finally {
+               System.out.println("stopping server");
+               server.stop();
+           }
+    }
+
+    private static String toString(Headers headers) {
+        return headers.entrySet().stream()
+                .map((e) -> e.getKey() + ": " + e.getValue())
+                .collect(Collectors.joining("\n"));
+    }
+
+    public static HTTPTestServer create(HttpProtocolType protocol,
+                                        HttpAuthType authType,
+                                        HttpTestAuthenticator auth,
+                                        HttpSchemeType schemeType)
+            throws IOException {
+        return create(protocol, authType, auth, schemeType, null);
+    }
+
+    public static HTTPTestServer create(HttpProtocolType protocol,
+                                        HttpAuthType authType,
+                                        HttpTestAuthenticator auth,
+                                        HttpSchemeType schemeType,
+                                        HttpHandler delegate)
+            throws IOException {
+        Objects.requireNonNull(authType);
+        Objects.requireNonNull(auth);
+        switch(authType) {
+            // A server that performs Server Digest authentication.
+            case SERVER: return createServer(protocol, authType, auth,
+                                             schemeType, delegate, "/");
+            // A server that pretends to be a Proxy and performs
+            // Proxy Digest authentication. If protocol is HTTPS,
+            // then this will create a HttpsProxyTunnel that will
+            // handle the CONNECT request for tunneling.
+            case PROXY: return createProxy(protocol, authType, auth,
+                                           schemeType, delegate, "/");
+            // A server that sends 307 redirect to a server that performs
+            // Digest authentication.
+            // Note: 301 doesn't work here because it transforms POST into GET.
+            case SERVER307: return createServerAndRedirect(protocol,
+                                                        HttpAuthType.SERVER,
+                                                        auth, schemeType,
+                                                        delegate, 307);
+            // A server that sends 305 redirect to a proxy that performs
+            // Digest authentication.
+            case PROXY305:  return createServerAndRedirect(protocol,
+                                                        HttpAuthType.PROXY,
+                                                        auth, schemeType,
+                                                        delegate, 305);
+            default:
+                throw new InternalError("Unknown server type: " + authType);
+        }
+    }
+
+    static HttpServer createHttpServer(HttpProtocolType protocol) throws IOException {
+        switch (protocol) {
+            case HTTP:  return HttpServer.create();
+            case HTTPS: return configure(HttpsServer.create());
+            default: throw new InternalError("Unsupported protocol " + protocol);
+        }
+    }
+
+    static HttpsServer configure(HttpsServer server) throws IOException {
+        try {
+            SSLContext ctx = SSLContext.getDefault();
+            server.setHttpsConfigurator(new Configurator(ctx));
+        } catch (NoSuchAlgorithmException ex) {
+            throw new IOException(ex);
+        }
+        return server;
+    }
+
+
+    static void setContextAuthenticator(HttpContext ctxt,
+                                        HttpTestAuthenticator auth) {
+        final String realm = auth.getRealm();
+        com.sun.net.httpserver.Authenticator authenticator =
+            new BasicAuthenticator(realm) {
+                @Override
+                public boolean checkCredentials(String username, String pwd) {
+                    return auth.getUserName().equals(username)
+                           && new String(auth.getPassword(username)).equals(pwd);
+                }
+        };
+        ctxt.setAuthenticator(authenticator);
+    }
+
+    public static HTTPTestServer createServer(HttpProtocolType protocol,
+                                        HttpAuthType authType,
+                                        HttpTestAuthenticator auth,
+                                        HttpSchemeType schemeType,
+                                        HttpHandler delegate,
+                                        String path)
+            throws IOException {
+        Objects.requireNonNull(authType);
+        Objects.requireNonNull(auth);
+
+        HttpServer impl = createHttpServer(protocol);
+        final HTTPTestServer server = new HTTPTestServer(impl, null, delegate);
+        final HttpHandler hh = server.createHandler(schemeType, auth, authType);
+        HttpContext ctxt = impl.createContext(path, hh);
+        server.configureAuthentication(ctxt, schemeType, auth, authType);
+        impl.bind(new InetSocketAddress("127.0.0.1", 0), 0);
+        impl.start();
+        return server;
+    }
+
+    public static HTTPTestServer createProxy(HttpProtocolType protocol,
+                                        HttpAuthType authType,
+                                        HttpTestAuthenticator auth,
+                                        HttpSchemeType schemeType,
+                                        HttpHandler delegate,
+                                        String path)
+            throws IOException {
+        Objects.requireNonNull(authType);
+        Objects.requireNonNull(auth);
+
+        HttpServer impl = createHttpServer(protocol);
+        final HTTPTestServer server = protocol == HttpProtocolType.HTTPS
+                ? new HttpsProxyTunnel(impl, null, delegate)
+                : new HTTPTestServer(impl, null, delegate);
+        final HttpHandler hh = server.createHandler(schemeType, auth, authType);
+        HttpContext ctxt = impl.createContext(path, hh);
+        server.configureAuthentication(ctxt, schemeType, auth, authType);
+
+        impl.bind(new InetSocketAddress("127.0.0.1", 0), 0);
+        impl.start();
+
+        return server;
+    }
+
+    public static HTTPTestServer createServerAndRedirect(
+                                        HttpProtocolType protocol,
+                                        HttpAuthType targetAuthType,
+                                        HttpTestAuthenticator auth,
+                                        HttpSchemeType schemeType,
+                                        HttpHandler targetDelegate,
+                                        int code300)
+            throws IOException {
+        Objects.requireNonNull(targetAuthType);
+        Objects.requireNonNull(auth);
+
+        // The connection between client and proxy can only
+        // be a plain connection: SSL connection to proxy
+        // is not supported by our client connection.
+        HttpProtocolType targetProtocol = targetAuthType == HttpAuthType.PROXY
+                                          ? HttpProtocolType.HTTP
+                                          : protocol;
+        HTTPTestServer redirectTarget =
+                (targetAuthType == HttpAuthType.PROXY)
+                ? createProxy(protocol, targetAuthType,
+                              auth, schemeType, targetDelegate, "/")
+                : createServer(targetProtocol, targetAuthType,
+                               auth, schemeType, targetDelegate, "/");
+        HttpServer impl = createHttpServer(protocol);
+        final HTTPTestServer redirectingServer =
+                 new HTTPTestServer(impl, redirectTarget, null);
+        InetSocketAddress redirectAddr = redirectTarget.getAddress();
+        URL locationURL = url(targetProtocol, redirectAddr, "/");
+        final HttpHandler hh = redirectingServer.create300Handler(locationURL,
+                                             HttpAuthType.SERVER, code300);
+        impl.createContext("/", hh);
+        impl.bind(new InetSocketAddress("127.0.0.1", 0), 0);
+        impl.start();
+        return redirectingServer;
+    }
+
+    public InetSocketAddress getAddress() {
+        return serverImpl.getAddress();
+    }
+
+    public void stop() {
+        serverImpl.stop(0);
+        if (redirect != null) {
+            redirect.stop();
+        }
+    }
+
+    protected void writeResponse(HttpExchange he) throws IOException {
+        if (delegate == null) {
+            he.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0);
+            he.getResponseBody().write(he.getRequestBody().readAllBytes());
+        } else {
+            delegate.handle(he);
+        }
+    }
+
+    private HttpHandler createHandler(HttpSchemeType schemeType,
+                                      HttpTestAuthenticator auth,
+                                      HttpAuthType authType) {
+        return new HttpNoAuthHandler(authType);
+    }
+
+    private void configureAuthentication(HttpContext ctxt,
+                            HttpSchemeType schemeType,
+                            HttpTestAuthenticator auth,
+                            HttpAuthType authType) {
+        switch(schemeType) {
+            case DIGEST:
+                // DIGEST authentication is handled by the handler.
+                ctxt.getFilters().add(new HttpDigestFilter(auth, authType));
+                break;
+            case BASIC:
+                // BASIC authentication is handled by the filter.
+                ctxt.getFilters().add(new HttpBasicFilter(auth, authType));
+                break;
+            case BASICSERVER:
+                switch(authType) {
+                    case PROXY: case PROXY305:
+                        // HttpServer can't support Proxy-type authentication
+                        // => we do as if BASIC had been specified, and we will
+                        //    handle authentication in the handler.
+                        ctxt.getFilters().add(new HttpBasicFilter(auth, authType));
+                        break;
+                    case SERVER: case SERVER307:
+                        // Basic authentication is handled by HttpServer
+                        // directly => the filter should not perform
+                        // authentication again.
+                        setContextAuthenticator(ctxt, auth);
+                        ctxt.getFilters().add(new HttpNoAuthFilter(authType));
+                        break;
+                    default:
+                        throw new InternalError("Invalid combination scheme="
+                             + schemeType + " authType=" + authType);
+                }
+            case NONE:
+                // No authentication at all.
+                ctxt.getFilters().add(new HttpNoAuthFilter(authType));
+                break;
+            default:
+                throw new InternalError("No such scheme: " + schemeType);
+        }
+    }
+
+    private HttpHandler create300Handler(URL proxyURL,
+        HttpAuthType type, int code300) throws MalformedURLException {
+        return new Http3xxHandler(proxyURL, type, code300);
+    }
+
+    // Abstract HTTP filter class.
+    private abstract static class AbstractHttpFilter extends Filter {
+
+        final HttpAuthType authType;
+        final String type;
+        public AbstractHttpFilter(HttpAuthType authType, String type) {
+            this.authType = authType;
+            this.type = type;
+        }
+
+        String getLocation() {
+            return "Location";
+        }
+        String getAuthenticate() {
+            return authType == HttpAuthType.PROXY
+                    ? "Proxy-Authenticate" : "WWW-Authenticate";
+        }
+        String getAuthorization() {
+            return authType == HttpAuthType.PROXY
+                    ? "Proxy-Authorization" : "Authorization";
+        }
+        int getUnauthorizedCode() {
+            return authType == HttpAuthType.PROXY
+                    ? HttpURLConnection.HTTP_PROXY_AUTH
+                    : HttpURLConnection.HTTP_UNAUTHORIZED;
+        }
+        String getKeepAlive() {
+            return "keep-alive";
+        }
+        String getConnection() {
+            return authType == HttpAuthType.PROXY
+                    ? "Proxy-Connection" : "Connection";
+        }
+        protected abstract boolean isAuthentified(HttpExchange he) throws IOException;
+        protected abstract void requestAuthentication(HttpExchange he) throws IOException;
+        protected void accept(HttpExchange he, Chain chain) throws IOException {
+            chain.doFilter(he);
+        }
+
+        @Override
+        public String description() {
+            return "Filter for " + type;
+        }
+        @Override
+        public void doFilter(HttpExchange he, Chain chain) throws IOException {
+            try {
+                System.out.println(type + ": Got " + he.getRequestMethod()
+                    + ": " + he.getRequestURI()
+                    + "\n" + HTTPTestServer.toString(he.getRequestHeaders()));
+                if (!isAuthentified(he)) {
+                    try {
+                        requestAuthentication(he);
+                        he.sendResponseHeaders(getUnauthorizedCode(), 0);
+                        System.out.println(type
+                            + ": Sent back " + getUnauthorizedCode());
+                    } finally {
+                        he.close();
+                    }
+                } else {
+                    accept(he, chain);
+                }
+            } catch (RuntimeException | Error | IOException t) {
+               System.err.println(type
+                    + ": Unexpected exception while handling request: " + t);
+               t.printStackTrace(System.err);
+               he.close();
+               throw t;
+            }
+        }
+
+    }
+
+    private final static class DigestResponse {
+        final String realm;
+        final String username;
+        final String nonce;
+        final String cnonce;
+        final String nc;
+        final String uri;
+        final String algorithm;
+        final String response;
+        final String qop;
+        final String opaque;
+
+        public DigestResponse(String realm, String username, String nonce,
+                              String cnonce, String nc, String uri,
+                              String algorithm, String qop, String opaque,
+                              String response) {
+            this.realm = realm;
+            this.username = username;
+            this.nonce = nonce;
+            this.cnonce = cnonce;
+            this.nc = nc;
+            this.uri = uri;
+            this.algorithm = algorithm;
+            this.qop = qop;
+            this.opaque = opaque;
+            this.response = response;
+        }
+
+        String getAlgorithm(String defval) {
+            return algorithm == null ? defval : algorithm;
+        }
+        String getQoP(String defval) {
+            return qop == null ? defval : qop;
+        }
+
+        // Code stolen from DigestAuthentication:
+
+        private static final char charArray[] = {
+            '0', '1', '2', '3', '4', '5', '6', '7',
+            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+        };
+
+        private static String encode(String src, char[] passwd, MessageDigest md) {
+            try {
+                md.update(src.getBytes("ISO-8859-1"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+                assert false;
+            }
+            if (passwd != null) {
+                byte[] passwdBytes = new byte[passwd.length];
+                for (int i=0; i<passwd.length; i++)
+                    passwdBytes[i] = (byte)passwd[i];
+                md.update(passwdBytes);
+                Arrays.fill(passwdBytes, (byte)0x00);
+            }
+            byte[] digest = md.digest();
+
+            StringBuilder res = new StringBuilder(digest.length * 2);
+            for (int i = 0; i < digest.length; i++) {
+                int hashchar = ((digest[i] >>> 4) & 0xf);
+                res.append(charArray[hashchar]);
+                hashchar = (digest[i] & 0xf);
+                res.append(charArray[hashchar]);
+            }
+            return res.toString();
+        }
+
+        public static String computeDigest(boolean isRequest,
+                                            String reqMethod,
+                                            char[] password,
+                                            DigestResponse params)
+            throws NoSuchAlgorithmException
+        {
+
+            String A1, HashA1;
+            String algorithm = params.getAlgorithm("MD5");
+            boolean md5sess = algorithm.equalsIgnoreCase ("MD5-sess");
+
+            MessageDigest md = MessageDigest.getInstance(md5sess?"MD5":algorithm);
+
+            if (params.username == null) {
+                throw new IllegalArgumentException("missing username");
+            }
+            if (params.realm == null) {
+                throw new IllegalArgumentException("missing realm");
+            }
+            if (params.uri == null) {
+                throw new IllegalArgumentException("missing uri");
+            }
+            if (params.nonce == null) {
+                throw new IllegalArgumentException("missing nonce");
+            }
+
+            A1 = params.username + ":" + params.realm + ":";
+            HashA1 = encode(A1, password, md);
+
+            String A2;
+            if (isRequest) {
+                A2 = reqMethod + ":" + params.uri;
+            } else {
+                A2 = ":" + params.uri;
+            }
+            String HashA2 = encode(A2, null, md);
+            String combo, finalHash;
+
+            if ("auth".equals(params.qop)) { /* RRC2617 when qop=auth */
+                if (params.cnonce == null) {
+                    throw new IllegalArgumentException("missing nonce");
+                }
+                if (params.nc == null) {
+                    throw new IllegalArgumentException("missing nonce");
+                }
+                combo = HashA1+ ":" + params.nonce + ":" + params.nc + ":" +
+                            params.cnonce + ":auth:" +HashA2;
+
+            } else { /* for compatibility with RFC2069 */
+                combo = HashA1 + ":" +
+                           params.nonce + ":" +
+                           HashA2;
+            }
+            finalHash = encode(combo, null, md);
+            return finalHash;
+        }
+
+        public static DigestResponse create(String raw) {
+            String username, realm, nonce, nc, uri, response, cnonce,
+                   algorithm, qop, opaque;
+            HeaderParser parser = new HeaderParser(raw);
+            username = parser.findValue("username");
+            realm = parser.findValue("realm");
+            nonce = parser.findValue("nonce");
+            nc = parser.findValue("nc");
+            uri = parser.findValue("uri");
+            cnonce = parser.findValue("cnonce");
+            response = parser.findValue("response");
+            algorithm = parser.findValue("algorithm");
+            qop = parser.findValue("qop");
+            opaque = parser.findValue("opaque");
+            return new DigestResponse(realm, username, nonce, cnonce, nc, uri,
+                                      algorithm, qop, opaque, response);
+        }
+
+    }
+
+    private class HttpNoAuthFilter extends AbstractHttpFilter {
+
+        public HttpNoAuthFilter(HttpAuthType authType) {
+            super(authType, authType == HttpAuthType.SERVER
+                            ? "NoAuth Server" : "NoAuth Proxy");
+        }
+
+        @Override
+        protected boolean isAuthentified(HttpExchange he) throws IOException {
+            return true;
+        }
+
+        @Override
+        protected void requestAuthentication(HttpExchange he) throws IOException {
+            throw new InternalError("Should not com here");
+        }
+
+        @Override
+        public String description() {
+            return "Passthrough Filter";
+        }
+
+    }
+
+    // An HTTP Filter that performs Basic authentication
+    private class HttpBasicFilter extends AbstractHttpFilter {
+
+        private final HttpTestAuthenticator auth;
+        public HttpBasicFilter(HttpTestAuthenticator auth, HttpAuthType authType) {
+            super(authType, authType == HttpAuthType.SERVER
+                            ? "Basic Server" : "Basic Proxy");
+            this.auth = auth;
+        }
+
+        @Override
+        protected void requestAuthentication(HttpExchange he)
+            throws IOException {
+            he.getResponseHeaders().add(getAuthenticate(),
+                 "Basic realm=\"" + auth.getRealm() + "\"");
+            System.out.println(type + ": Requesting Basic Authentication "
+                 + he.getResponseHeaders().getFirst(getAuthenticate()));
+        }
+
+        @Override
+        protected boolean isAuthentified(HttpExchange he) {
+            if (he.getRequestHeaders().containsKey(getAuthorization())) {
+                List<String> authorization =
+                    he.getRequestHeaders().get(getAuthorization());
+                for (String a : authorization) {
+                    System.out.println(type + ": processing " + a);
+                    int sp = a.indexOf(' ');
+                    if (sp < 0) return false;
+                    String scheme = a.substring(0, sp);
+                    if (!"Basic".equalsIgnoreCase(scheme)) {
+                        System.out.println(type + ": Unsupported scheme '"
+                                           + scheme +"'");
+                        return false;
+                    }
+                    if (a.length() <= sp+1) {
+                        System.out.println(type + ": value too short for '"
+                                            + scheme +"'");
+                        return false;
+                    }
+                    a = a.substring(sp+1);
+                    return validate(a);
+                }
+                return false;
+            }
+            return false;
+        }
+
+        boolean validate(String a) {
+            byte[] b = Base64.getDecoder().decode(a);
+            String userpass = new String (b);
+            int colon = userpass.indexOf (':');
+            String uname = userpass.substring (0, colon);
+            String pass = userpass.substring (colon+1);
+            return auth.getUserName().equals(uname) &&
+                   new String(auth.getPassword(uname)).equals(pass);
+        }
+
+        @Override
+        public String description() {
+            return "Filter for " + type;
+        }
+
+    }
+
+
+    // An HTTP Filter that performs Digest authentication
+    private class HttpDigestFilter extends AbstractHttpFilter {
+
+        // This is a very basic DIGEST - used only for the purpose of testing
+        // the client implementation. Therefore we can get away with never
+        // updating the server nonce as it makes the implementation of the
+        // server side digest simpler.
+        private final HttpTestAuthenticator auth;
+        private final byte[] nonce;
+        private final String ns;
+        public HttpDigestFilter(HttpTestAuthenticator auth, HttpAuthType authType) {
+            super(authType, authType == HttpAuthType.SERVER
+                            ? "Digest Server" : "Digest Proxy");
+            this.auth = auth;
+            nonce = new byte[16];
+            new Random(Instant.now().toEpochMilli()).nextBytes(nonce);
+            ns = new BigInteger(1, nonce).toString(16);
+        }
+
+        @Override
+        protected void requestAuthentication(HttpExchange he)
+            throws IOException {
+            he.getResponseHeaders().add(getAuthenticate(),
+                 "Digest realm=\"" + auth.getRealm() + "\","
+                 + "\r\n    qop=\"auth\","
+                 + "\r\n    nonce=\"" + ns +"\"");
+            System.out.println(type + ": Requesting Digest Authentication "
+                 + he.getResponseHeaders().getFirst(getAuthenticate()));
+        }
+
+        @Override
+        protected boolean isAuthentified(HttpExchange he) {
+            if (he.getRequestHeaders().containsKey(getAuthorization())) {
+                List<String> authorization = he.getRequestHeaders().get(getAuthorization());
+                for (String a : authorization) {
+                    System.out.println(type + ": processing " + a);
+                    int sp = a.indexOf(' ');
+                    if (sp < 0) return false;
+                    String scheme = a.substring(0, sp);
+                    if (!"Digest".equalsIgnoreCase(scheme)) {
+                        System.out.println(type + ": Unsupported scheme '" + scheme +"'");
+                        return false;
+                    }
+                    if (a.length() <= sp+1) {
+                        System.out.println(type + ": value too short for '" + scheme +"'");
+                        return false;
+                    }
+                    a = a.substring(sp+1);
+                    DigestResponse dgr = DigestResponse.create(a);
+                    return validate(he.getRequestMethod(), dgr);
+                }
+                return false;
+            }
+            return false;
+        }
+
+        boolean validate(String reqMethod, DigestResponse dg) {
+            if (!"MD5".equalsIgnoreCase(dg.getAlgorithm("MD5"))) {
+                System.out.println(type + ": Unsupported algorithm "
+                                   + dg.algorithm);
+                return false;
+            }
+            if (!"auth".equalsIgnoreCase(dg.getQoP("auth"))) {
+                System.out.println(type + ": Unsupported qop "
+                                   + dg.qop);
+                return false;
+            }
+            try {
+                if (!dg.nonce.equals(ns)) {
+                    System.out.println(type + ": bad nonce returned by client: "
+                                    + nonce + " expected " + ns);
+                    return false;
+                }
+                if (dg.response == null) {
+                    System.out.println(type + ": missing digest response.");
+                    return false;
+                }
+                char[] pa = auth.getPassword(dg.username);
+                return verify(reqMethod, dg, pa);
+            } catch(IllegalArgumentException | SecurityException
+                    | NoSuchAlgorithmException e) {
+                System.out.println(type + ": " + e.getMessage());
+                return false;
+            }
+        }
+
+        boolean verify(String reqMethod, DigestResponse dg, char[] pw)
+            throws NoSuchAlgorithmException {
+            String response = DigestResponse.computeDigest(true, reqMethod, pw, dg);
+            if (!dg.response.equals(response)) {
+                System.out.println(type + ": bad response returned by client: "
+                                    + dg.response + " expected " + response);
+                return false;
+            } else {
+                System.out.println(type + ": verified response " + response);
+            }
+            return true;
+        }
+
+        @Override
+        public String description() {
+            return "Filter for DIGEST authentication";
+        }
+    }
+
+    // Abstract HTTP handler class.
+    private abstract static class AbstractHttpHandler implements HttpHandler {
+
+        final HttpAuthType authType;
+        final String type;
+        public AbstractHttpHandler(HttpAuthType authType, String type) {
+            this.authType = authType;
+            this.type = type;
+        }
+
+        String getLocation() {
+            return "Location";
+        }
+
+        @Override
+        public void handle(HttpExchange he) throws IOException {
+            try {
+                sendResponse(he);
+            } catch (RuntimeException | Error | IOException t) {
+               System.err.println(type
+                    + ": Unexpected exception while handling request: " + t);
+               t.printStackTrace(System.err);
+               throw t;
+            } finally {
+                he.close();
+            }
+        }
+
+        protected abstract void sendResponse(HttpExchange he) throws IOException;
+
+    }
+
+    private class HttpNoAuthHandler extends AbstractHttpHandler {
+
+        public HttpNoAuthHandler(HttpAuthType authType) {
+            super(authType, authType == HttpAuthType.SERVER
+                            ? "NoAuth Server" : "NoAuth Proxy");
+        }
+
+        @Override
+        protected void sendResponse(HttpExchange he) throws IOException {
+            HTTPTestServer.this.writeResponse(he);
+        }
+
+    }
+
+    // A dummy HTTP Handler that redirects all incoming requests
+    // by sending a back 3xx response code (301, 305, 307 etc..)
+    private class Http3xxHandler extends AbstractHttpHandler {
+
+        private final URL redirectTargetURL;
+        private final int code3XX;
+        public Http3xxHandler(URL proxyURL, HttpAuthType authType, int code300) {
+            super(authType, "Server" + code300);
+            this.redirectTargetURL = proxyURL;
+            this.code3XX = code300;
+        }
+
+        int get3XX() {
+            return code3XX;
+        }
+
+        @Override
+        public void sendResponse(HttpExchange he) throws IOException {
+            System.out.println(type + ": Got " + he.getRequestMethod()
+                    + ": " + he.getRequestURI()
+                    + "\n" + HTTPTestServer.toString(he.getRequestHeaders()));
+            System.out.println(type + ": Redirecting to "
+                               + (authType == HttpAuthType.PROXY305
+                                    ? "proxy" : "server"));
+            he.getResponseHeaders().add(getLocation(),
+                redirectTargetURL.toExternalForm().toString());
+            he.sendResponseHeaders(get3XX(), 0);
+            System.out.println(type + ": Sent back " + get3XX() + " "
+                 + getLocation() + ": " + redirectTargetURL.toExternalForm().toString());
+        }
+    }
+
+    static class Configurator extends HttpsConfigurator {
+        public Configurator(SSLContext ctx) {
+            super(ctx);
+        }
+
+        @Override
+        public void configure (HttpsParameters params) {
+            params.setSSLParameters (getSSLContext().getSupportedSSLParameters());
+        }
+    }
+
+    // This is a bit hacky: HttpsProxyTunnel is an HTTPTestServer hidden
+    // behind a fake proxy that only understands CONNECT requests.
+    // The fake proxy is just a server socket that intercept the
+    // CONNECT and then redirect streams to the real server.
+    static class HttpsProxyTunnel extends HTTPTestServer
+            implements Runnable {
+
+        final ServerSocket ss;
+        public HttpsProxyTunnel(HttpServer server, HTTPTestServer target,
+                               HttpHandler delegate)
+                throws IOException {
+            super(server, target, delegate);
+            System.out.flush();
+            System.err.println("WARNING: HttpsProxyTunnel is an experimental test class");
+            ss = new ServerSocket(0, 0, InetAddress.getByName("127.0.0.1"));
+            start();
+        }
+
+        final void start() throws IOException {
+            Thread t = new Thread(this, "ProxyThread");
+            t.setDaemon(true);
+            t.start();
+        }
+
+        @Override
+        public void stop() {
+            super.stop();
+            try {
+                ss.close();
+            } catch (IOException ex) {
+                if (DEBUG) ex.printStackTrace(System.out);
+            }
+        }
+
+        // Pipe the input stream to the output stream.
+        private synchronized Thread pipe(InputStream is, OutputStream os, char tag) {
+            return new Thread("TunnelPipe("+tag+")") {
+                @Override
+                public void run() {
+                    try {
+                        try {
+                            int c;
+                            while ((c = is.read()) != -1) {
+                                os.write(c);
+                                os.flush();
+                                // if DEBUG prints a + or a - for each transferred
+                                // character.
+                                if (DEBUG) System.out.print(tag);
+                            }
+                            is.close();
+                        } finally {
+                            os.close();
+                        }
+                    } catch (IOException ex) {
+                        if (DEBUG) ex.printStackTrace(System.out);
+                    }
+                }
+            };
+        }
+
+        @Override
+        public InetSocketAddress getAddress() {
+            return new InetSocketAddress(ss.getInetAddress(), ss.getLocalPort());
+        }
+
+        // This is a bit shaky. It doesn't handle continuation
+        // lines, but our client shouldn't send any.
+        // Read a line from the input stream, swallowing the final
+        // \r\n sequence. Stops at the first \n, doesn't complain
+        // if it wasn't preceded by '\r'.
+        //
+        String readLine(InputStream r) throws IOException {
+            StringBuilder b = new StringBuilder();
+            int c;
+            while ((c = r.read()) != -1) {
+                if (c == '\n') break;
+                b.appendCodePoint(c);
+            }
+            if (b.codePointAt(b.length() -1) == '\r') {
+                b.delete(b.length() -1, b.length());
+            }
+            return b.toString();
+        }
+
+        @Override
+        public void run() {
+            Socket clientConnection = null;
+            try {
+                while (true) {
+                    System.out.println("Tunnel: Waiting for client");
+                    Socket previous = clientConnection;
+                    try {
+                        clientConnection = ss.accept();
+                    } catch (IOException io) {
+                        if (DEBUG) io.printStackTrace(System.out);
+                        break;
+                    } finally {
+                        // close the previous connection
+                        if (previous != null) previous.close();
+                    }
+                    System.out.println("Tunnel: Client accepted");
+                    Socket targetConnection = null;
+                    InputStream  ccis = clientConnection.getInputStream();
+                    OutputStream ccos = clientConnection.getOutputStream();
+                    Writer w = new OutputStreamWriter(
+                                   clientConnection.getOutputStream(), "UTF-8");
+                    PrintWriter pw = new PrintWriter(w);
+                    System.out.println("Tunnel: Reading request line");
+                    String requestLine = readLine(ccis);
+                    System.out.println("Tunnel: Request line: " + requestLine);
+                    if (requestLine.startsWith("CONNECT ")) {
+                        // We should probably check that the next word following
+                        // CONNECT is the host:port of our HTTPS serverImpl.
+                        // Some improvement for a followup!
+
+                        // Read all headers until we find the empty line that
+                        // signals the end of all headers.
+                        while(!requestLine.equals("")) {
+                            System.out.println("Tunnel: Reading header: "
+                                               + (requestLine = readLine(ccis)));
+                        }
+
+                        targetConnection = new Socket(
+                                serverImpl.getAddress().getAddress(),
+                                serverImpl.getAddress().getPort());
+
+                        // Then send the 200 OK response to the client
+                        System.out.println("Tunnel: Sending "
+                                           + "HTTP/1.1 200 OK\r\n\r\n");
+                        pw.print("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+                        pw.flush();
+                    } else {
+                        // This should not happen. If it does let our serverImpl
+                        // deal with it.
+                        throw new IOException("Tunnel: Unexpected status line: "
+                                             + requestLine);
+                    }
+
+                    // Pipe the input stream of the client connection to the
+                    // output stream of the target connection and conversely.
+                    // Now the client and target will just talk to each other.
+                    System.out.println("Tunnel: Starting tunnel pipes");
+                    Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+');
+                    Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-');
+                    t1.start();
+                    t2.start();
+
+                    // We have only 1 client... wait until it has finished before
+                    // accepting a new connection request.
+                    t1.join();
+                    t2.join();
+                }
+            } catch (Throwable ex) {
+                try {
+                    ss.close();
+                } catch (IOException ex1) {
+                    ex.addSuppressed(ex1);
+                }
+                ex.printStackTrace(System.err);
+            }
+        }
+
+    }
+}
--- a/jdk/test/java/net/HttpURLConnection/getResponseCode.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/net/HttpURLConnection/getResponseCode.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,6 +24,8 @@
 /*
  * @test
  * @bug 4666195
+ * @build getResponseCode
+ * @run main getResponseCode
  * @summary REGRESSION: HttpURLConnection.getResponseCode() returns always -1
 */
 import java.net.*;
--- a/jdk/test/java/net/InterfaceAddress/Equals.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/net/InterfaceAddress/Equals.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,7 @@
 
 /* @test
  * @bug 6628576
+ * @modules java.base/java.net:open
  * @summary InterfaceAddress.equals() NPE when broadcast field == null
  */
 
--- a/jdk/test/java/nio/Buffer/Basic.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/nio/Buffer/Basic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,8 @@
  *      4526177 4463011 4660660 4661219 4663521 4782970 4804304 4938424 6231529
  *      6221101 6234263 6535542 6591971 6593946 6795561 7190219 7199551 8065556
  *      8149469
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/java.nio:open
+ *          java.base/jdk.internal.misc
  * @author Mark Reinhold
  */
 
--- a/jdk/test/java/nio/channels/Selector/TemporarySelector.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/nio/channels/Selector/TemporarySelector.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,7 +23,7 @@
 
 /* @test
  * @bug 6645197
- * @run main/othervm -Xmx5m TemporarySelector
+ * @run main/othervm -Xmx16m TemporarySelector
  * @summary Timed read with socket adaptor throws ClosedSelectorException if temporary selector GC'ed.
  */
 import java.io.IOException;
--- a/jdk/test/java/nio/channels/Selector/Wakeup.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/nio/channels/Selector/Wakeup.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2008, 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
@@ -24,14 +24,14 @@
 /* @test
  * @bug 6405995
  * @summary Unit test for selector wakeup and interruption
- * @library ..
+ * @library .. /lib/testlibrary/
  */
 
 import java.io.*;
 import java.net.*;
 import java.nio.*;
 import java.nio.channels.*;
-import java.util.Random;
+import java.util.concurrent.CyclicBarrier;
 
 public class Wakeup {
 
@@ -44,91 +44,112 @@
     }
 
     static class Sleeper extends TestThread {
+        private static final long TIMEOUT = jdk.testlibrary.Utils.adjustTimeout(20_000);
+
+        // barrier is used to synchronize sleeper thread and checking
+        // thread which is the main thread: when go() get to the end,
+        // then start checking the sleeper's status.
+        private static CyclicBarrier barrier = new CyclicBarrier(2);
+        private static int wakeups = 0;
+        private static int waits = 0;
+
+        volatile boolean interruptBeforeSelect = false;
         volatile boolean started = false;
-        volatile int entries = 0;
-        volatile int wakeups = 0;
         volatile boolean wantInterrupt = false;
-        volatile boolean gotInterrupt = false;
-        volatile Exception exception = null;
         volatile boolean closed = false;
         Object gate = new Object();
 
         Selector sel;
 
-        Sleeper(Selector sel) {
+        Sleeper(Selector sel, boolean wantInterrupt, boolean interruptBeforeSelect) {
             super("Sleeper", System.err);
             this.sel = sel;
+            this.wantInterrupt = wantInterrupt;
+            this.interruptBeforeSelect = interruptBeforeSelect;
         }
 
         public void go() throws Exception {
             started = true;
-            for (;;) {
+            if (interruptBeforeSelect) {
                 synchronized (gate) { }
-                entries++;
-                try {
-                    sel.select();
-                } catch (ClosedSelectorException x) {
-                    closed = true;
+            }
+            wakeups++;
+            System.err.println("Wakeup, selecting, " + wakeups);
+            try {
+                sel.select();
+            } catch (ClosedSelectorException x) {
+                closed = true;
+            }
+            boolean intr = Thread.currentThread().isInterrupted();
+            System.err.println("Wakeup " + wakeups
+                               + (closed ? " (closed)" : "")
+                               + (intr ? " (intr)" : ""));
+            if (closed)
+                return;
+            if (wantInterrupt) {
+                while (!Thread.interrupted())
+                    Thread.yield();
+            }
+            System.err.println("Wakeup, waiting, " + wakeups);
+            barrier.await();
+            System.err.println("Wakeup, wait successfully, " + wakeups);
+        }
+
+        void check(boolean close) throws Exception {
+            waits++;
+            System.err.println("waiting sleeper, " + waits);
+            if (!close) {
+                barrier.await();
+                System.err.println("wait barrier successfully, " + waits);
+            }
+            if (finish(TIMEOUT) == 0)
+                throw new Exception("Test failed");
+            if (this.closed != close)
+                throw new Exception("Selector was closed");
+        }
+
+        void check() throws Exception {
+            check(false);
+        }
+
+        static Sleeper createSleeper(Selector sel, boolean wantInterrupt,
+                boolean interruptBeforeSelect) throws Exception {
+            if (!wantInterrupt && interruptBeforeSelect) {
+                throw new RuntimeException("Wrong parameters!");
+            }
+
+            Sleeper sleeper = new Sleeper(sel, wantInterrupt, interruptBeforeSelect);
+
+            if (interruptBeforeSelect) {
+                synchronized(sleeper.gate) {
+                    sleeper.start();
+                    while (!sleeper.started)
+                        sleep(50);
+                    sleeper.interrupt();
                 }
-                boolean intr = Thread.currentThread().isInterrupted();
-                wakeups++;
-                System.err.println("Wakeup " + wakeups
-                                   + (closed ? " (closed)" : "")
-                                   + (intr ? " (intr)" : ""));
-                if (wakeups > 1000)
-                    throw new Exception("Too many wakeups");
-                if (closed)
-                    return;
+            } else {
+                sleeper.start();
+                while (!sleeper.started)
+                    sleep(50);
                 if (wantInterrupt) {
-                    while (!Thread.interrupted())
-                        Thread.yield();
-                    gotInterrupt = true;
-                    wantInterrupt = false;
+                    sleep(50);
+                    sleeper.interrupt();
                 }
             }
+            return sleeper;
         }
-
     }
 
-    private static int checkedWakeups = 0;
+    static Sleeper newSleeper(Selector sel) throws Exception {
+        return Sleeper.createSleeper(sel, false, false);
+    }
 
-    private static void check(Sleeper sleeper, boolean intr)
-        throws Exception
-    {
-        checkedWakeups++;
-        if (sleeper.wakeups > checkedWakeups) {
-            sleeper.finish(100);
-            throw new Exception("Sleeper has run ahead");
-        }
-        int n = 0;
-        while (sleeper.wakeups < checkedWakeups) {
-            sleep(50);
-            if ((n += 50) > 1000) {
-                sleeper.finish(100);
-                throw new Exception("Sleeper appears to be dead ("
-                                    + checkedWakeups + ")");
-            }
-        }
-        if (sleeper.wakeups > checkedWakeups) {
-            sleeper.finish(100);
-            throw new Exception("Too many wakeups: Expected "
-                                + checkedWakeups
-                                + ", got " + sleeper.wakeups);
-        }
-        if (intr) {
-            n = 0;
-            // Interrupts can sometimes be delayed, so wait
-            while (!sleeper.gotInterrupt) {
-                sleep(50);
-                if ((n += 50) > 1000) {
-                    sleeper.finish(100);
-                    throw new Exception("Interrupt never delivered");
-                }
-            }
-            sleeper.gotInterrupt = false;
-        }
-        System.err.println("Check " + checkedWakeups
-                           + (intr ? " (intr " + n + ")" : ""));
+    static Sleeper newSleeperWantInterrupt(Selector sel) throws Exception {
+        return Sleeper.createSleeper(sel, true, false);
+    }
+
+    static Sleeper newSleeperWantInterruptBeforeSelect(Selector sel) throws Exception {
+        return Sleeper.createSleeper(sel, true, true);
     }
 
     public static void main(String[] args) throws Exception {
@@ -138,60 +159,37 @@
         // Wakeup before select
         sel.wakeup();
 
-        Sleeper sleeper = new Sleeper(sel);
-
-        sleeper.start();
-        while (!sleeper.started)
-            sleep(50);
-
-        check(sleeper, false);          // 1
+        Sleeper sleeper = newSleeper(sel); // 1
+        sleeper.check();
 
         for (int i = 2; i < 5; i++) {
             // Wakeup during select
+            sleeper = newSleeper(sel);
             sel.wakeup();
-            check(sleeper, false);      // 2 .. 4
+            sleeper.check();         // 2 .. 4
         }
 
         // Double wakeup
-        synchronized (sleeper.gate) {
-            sel.wakeup();
-            check(sleeper, false);      // 5
-            sel.wakeup();
-            sel.wakeup();
-        }
-        check(sleeper, false);          // 6
+        sel.wakeup();
+        sel.wakeup();
+        sleeper = newSleeper(sel);
+        sleeper.check();            // 5
 
         // Interrupt
-        synchronized (sleeper.gate) {
-            sleeper.wantInterrupt = true;
-            sleeper.interrupt();
-            check(sleeper, true);       // 7
-        }
+        sleeper = newSleeperWantInterrupt(sel);
+        sleeper.check();            // 6
 
         // Interrupt before select
-        while (sleeper.entries < 8)
-            Thread.yield();
-        synchronized (sleeper.gate) {
-            sel.wakeup();
-            check(sleeper, false);      // 8
-            sleeper.wantInterrupt = true;
-            sleeper.interrupt();
-            sleep(50);
-        }
-        check(sleeper, true);           // 9
+        sleeper = newSleeperWantInterruptBeforeSelect(sel);
+        sleeper.check();            // 7
 
         // Close during select
-        while (sleeper.entries < 10)
-            Thread.yield();
-        synchronized (sleeper.gate) {
-            sel.close();
-            check(sleeper, false);      // 10
-        }
+        sleeper = newSleeper(sel);
+        sel.close();
+        sleeper.check();           // 8
 
-        if (sleeper.finish(200) == 0)
-            throw new Exception("Test failed");
-        if (!sleeper.closed)
-            throw new Exception("Selector not closed");
+        sleeper = newSleeper(sel);
+        sleeper.check(true);
     }
 
 }
--- a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -109,7 +109,8 @@
 
 go() {
     echo ''
-    sh -xc "$JAVA ${TESTVMOPTS} --add-exports java.base/sun.nio.ch=ALL-UNNAMED $DFLAG \
+    sh -xc "$JAVA ${TESTVMOPTS} --add-opens java.base/java.io=ALL-UNNAMED \
+            --add-opens java.base/sun.nio.ch=ALL-UNNAMED $DFLAG \
         $1 $2 $3 $4 $5 $6 $7 $8" 2>&1
     if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
 }
--- a/jdk/test/java/nio/file/etc/Exceptions.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/nio/file/etc/Exceptions.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,7 @@
 
 /* @test
  * @bug 4313887 6881498
+ * @modules java.base/java.lang:open
  * @summary Miscellenous tests on exceptions in java.nio.file
  */
 
--- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java	Wed Jul 05 22:32:06 2017 +0200
@@ -37,7 +37,7 @@
  *
  * @library ../../../testlibrary
  * @modules java.rmi/sun.rmi.registry
- *          java.rmi/sun.rmi.server
+ *          java.rmi/sun.rmi.server:+open
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
  *          java.base/sun.nio.ch
--- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -93,9 +93,8 @@
             obj = new CallbackImpl();
             Callback proxy =
                 (Callback) UnicastRemoteObject.exportObject(obj, 0);
-            Registry registry =
-                LocateRegistry.createRegistry(
-                    TestLibrary.INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT);
+            Registry registry = TestLibrary.createRegistryOnEphemeralPort();
+            int registryPort = TestLibrary.getRegistryPort(registry);
             registry.bind("Callback", proxy);
 
             /*
@@ -107,7 +106,8 @@
                                    TestLibrary.INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT);
             rmid.addOptions(
                 "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED",
-                "-Djava.nio.channels.spi.SelectorProvider=InheritedChannelNotServerSocket$SP");
+                "-Djava.nio.channels.spi.SelectorProvider=InheritedChannelNotServerSocket$SP",
+                "-Dtest.java.rmi.rmidViaInheritedChannel.registry.port=" + registryPort);
             rmid.start();
 
             /*
@@ -181,8 +181,9 @@
                  */
                 try {
                     System.err.println("notify test...");
-                    Registry registry =
-                        LocateRegistry.getRegistry(TestLibrary.INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT);
+                    int registryPort = Integer.getInteger(
+                            "test.java.rmi.rmidViaInheritedChannel.registry.port", 0);
+                    Registry registry = LocateRegistry.getRegistry(registryPort);
                     Callback obj = (Callback) registry.lookup("Callback");
                     obj.notifyTest();
                 } catch (NotBoundException nbe) {
--- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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 4295885 6824141
- * @summary rmid should be startable from inetd
- * @author Ann Wollrath
- *
- * @library ../../testlibrary
- * @modules java.base/sun.nio.ch
- *          java.rmi/sun.rmi.registry
- *          java.rmi/sun.rmi.server
- *          java.rmi/sun.rmi.transport
- *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary RMID ActivationLibrary
- * @run main/othervm/timeout=240 RmidViaInheritedChannel
- * @key intermittent
- */
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.ProtocolFamily;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
-import java.rmi.Remote;
-import java.rmi.NotBoundException;
-import java.rmi.activation.ActivationGroup;
-import java.rmi.activation.ActivationSystem;
-import java.rmi.registry.LocateRegistry;
-import java.rmi.registry.Registry;
-import java.rmi.server.UnicastRemoteObject;
-import static java.net.StandardSocketOptions.SO_REUSEADDR;
-import static java.net.StandardSocketOptions.SO_REUSEPORT;
-
-public class RmidViaInheritedChannel implements Callback {
-    private static final Object lock = new Object();
-    private static boolean notified = false;
-
-    private RmidViaInheritedChannel() {}
-
-    public void notifyTest() {
-        synchronized (lock) {
-            notified = true;
-            System.err.println("notification received.");
-            lock.notifyAll();
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        System.setProperty("java.rmi.activation.port",
-                           Integer.toString(TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT));
-        RMID rmid = null;
-        Callback obj = null;
-
-        try {
-            /*
-             * Export callback object and bind in registry.
-             */
-            System.err.println("export callback object and bind in registry");
-            obj = new RmidViaInheritedChannel();
-            Callback proxy = (Callback)
-                UnicastRemoteObject.exportObject(obj, 0);
-            Registry registry =
-                LocateRegistry.createRegistry(
-                    TestLibrary.RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT);
-            registry.bind("Callback", proxy);
-
-            /*
-             * Start rmid.
-             */
-            System.err.println("start rmid with inherited channel");
-            RMID.removeLog();
-            rmid = RMID.createRMID(System.out, System.err, true, false,
-                                   TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT);
-            rmid.addOptions(
-                "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED",
-                "-Djava.nio.channels.spi.SelectorProvider=RmidViaInheritedChannel$RmidSelectorProvider");
-            if (System.getProperty("os.name").startsWith("Windows") &&
-                System.getProperty("os.version").startsWith("5."))
-            {
-                /* Windows XP/2003 or older
-                 * Need to expand ephemeral range to include RMI test ports
-                 */
-                rmid.addOptions(new String[]{
-                    "-Djdk.net.ephemeralPortRange.low=1024",
-                    "-Djdk.net.ephemeralPortRange.high=64000"
-                });
-            }
-            rmid.start();
-
-            /*
-             * Get activation system and wait to be notified via callback
-             * from rmid's selector provider.
-             */
-            System.err.println("get activation system");
-            ActivationSystem system = ActivationGroup.getSystem();
-            System.err.println("ActivationSystem = " + system);
-            synchronized (lock) {
-                while (!notified) {
-                    lock.wait();
-                }
-            }
-            System.err.println("TEST PASSED");
-
-        } finally {
-            if (obj != null) {
-                UnicastRemoteObject.unexportObject(obj, true);
-            }
-            if (rmid != null) {
-                rmid.cleanup();
-            }
-        }
-    }
-
-    public static class RmidSelectorProvider extends SelectorProvider {
-
-        private final SelectorProvider provider;
-        private ServerSocketChannel channel = null;
-
-        public RmidSelectorProvider() {
-            provider =  sun.nio.ch.DefaultSelectorProvider.create();
-        }
-
-        public DatagramChannel openDatagramChannel()
-            throws IOException
-        {
-            return provider.openDatagramChannel();
-        }
-
-        public DatagramChannel openDatagramChannel(ProtocolFamily family)
-            throws IOException
-        {
-            return provider.openDatagramChannel(family);
-        }
-
-        public Pipe openPipe()
-            throws IOException
-        {
-            return provider.openPipe();
-        }
-
-        public AbstractSelector openSelector()
-            throws IOException
-        {
-            return provider.openSelector();
-        }
-
-        public ServerSocketChannel openServerSocketChannel()
-            throws IOException
-        {
-            return provider.openServerSocketChannel();
-        }
-
-        public SocketChannel openSocketChannel()
-             throws IOException
-        {
-            return provider.openSocketChannel();
-        }
-
-        public synchronized Channel inheritedChannel() throws IOException {
-            System.err.println("RmidSelectorProvider.inheritedChannel");
-            if (channel == null) {
-                /*
-                 * Create server socket channel and bind server socket.
-                 */
-                channel = ServerSocketChannel.open();
-                ServerSocket serverSocket = channel.socket();
-
-                // Enable SO_REUSEADDR before binding
-                serverSocket.setOption(SO_REUSEADDR, true);
-
-                // Enable SO_REUSEPORT, if supported, before binding
-                if (serverSocket.supportedOptions().contains(SO_REUSEPORT)) {
-                    serverSocket.setOption(SO_REUSEPORT, true);
-                }
-
-                serverSocket.bind(
-                     new InetSocketAddress(InetAddress.getLocalHost(),
-                     TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT));
-                System.err.println("serverSocket = " + serverSocket);
-
-                /*
-                 * Notify test that inherited channel was created.
-                 */
-                try {
-                    System.err.println("notify test...");
-                    Registry registry =
-                        LocateRegistry.getRegistry(TestLibrary.RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT);
-                    Callback obj = (Callback) registry.lookup("Callback");
-                    obj.notifyTest();
-                } catch (NotBoundException nbe) {
-                    throw (IOException)
-                        new IOException("callback object not bound").
-                            initCause(nbe);
-                }
-            }
-            return channel;
-        }
-    }
-}
-
-interface Callback extends Remote {
-    void notifyTest() throws IOException;
-}
--- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/rmid.security.policy	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/rmid.security.policy	Wed Jul 05 22:32:06 2017 +0200
@@ -3,4 +3,5 @@
     permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
     permission java.net.SocketPermission "*", "connect,accept";
     permission java.util.PropertyPermission "java.rmi.activation.port", "write";
+    permission java.util.PropertyPermission "test.java.rmi.rmidViaInheritedChannel.registry.port", "read";
 };
--- a/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,7 +30,7 @@
  * rather than pinning it indefinitely.
  * @author Peter Jones
  *
- * @modules java.rmi/sun.rmi.transport
+ * @modules java.rmi/sun.rmi.transport:+open
  * @build DGCAckFailure DGCAckFailure_Stub
  * @run main/othervm DGCAckFailure
  */
--- a/jdk/test/java/rmi/registry/interfaceHash/InterfaceHash.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/registry/interfaceHash/InterfaceHash.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, 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
@@ -42,7 +42,6 @@
  *          java.rmi/sun.rmi.transport.tcp
  * @build TestLibrary ReferenceRegistryStub
  * @run main/othervm InterfaceHash
- * @key intermittent
  */
 
 import java.lang.reflect.Constructor;
@@ -63,7 +62,6 @@
 
 public class InterfaceHash {
 
-    private static final int PORT = TestLibrary.getUnusedRandomPort();
     private static final String NAME = "WMM";
 
     public static void main(String[] args) throws Exception {
@@ -73,12 +71,13 @@
             "\n=== verifying that J2SE registry's skeleton uses" +
             "\ncorrect interface hash and operation numbers:");
 
-        Registry testImpl = LocateRegistry.createRegistry(PORT);
-        System.err.println("created test registry on port " + PORT);
+        Registry testImpl = TestLibrary.createRegistryOnEphemeralPort();
+        int regPort = TestLibrary.getRegistryPort(testImpl);
+        System.err.println("created test registry on port " + regPort);
 
         RemoteRef ref = new UnicastRef(
             new LiveRef(new ObjID(ObjID.REGISTRY_ID),
-                        new TCPEndpoint("", PORT), false));
+                        new TCPEndpoint("", regPort), false));
         Registry referenceStub = new ReferenceRegistryStub(ref);
         System.err.println("created reference registry stub: " +
                            referenceStub);
@@ -144,7 +143,7 @@
         }
         FakeRemoteRef f = new FakeRemoteRef();
 
-        Registry testRegistry = LocateRegistry.getRegistry(PORT);
+        Registry testRegistry = LocateRegistry.getRegistry(regPort);
         System.err.println("created original test registry stub: " +
                            testRegistry);
 
--- a/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,7 @@
  * @summary Tests proper parsing and defaulting of the
  * "java.rmi.server.useCodebaseOnly" property.
  *
- * @modules java.rmi/sun.rmi.server
+ * @modules java.rmi/sun.rmi.server:+open
  * @run main/othervm UseCodebaseOnlyDefault true
  * @run main/othervm -Djava.rmi.server.useCodebaseOnly=xyzzy UseCodebaseOnlyDefault true
  * @run main/othervm -Djava.rmi.server.useCodebaseOnly UseCodebaseOnlyDefault true
--- a/jdk/test/java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java	Wed Jul 05 22:32:06 2017 +0200
@@ -43,7 +43,6 @@
  *          java.rmi/sun.rmi.transport.tcp
  * @build TestLibrary JavaVM LeaseCheckInterval_Stub SelfTerminator
  * @run main/othervm LeaseCheckInterval
- * @key intermittent
  */
 
 import java.rmi.Remote;
@@ -88,9 +87,8 @@
             UnicastRemoteObject.exportObject(obj);
             System.err.println("exported remote object");
 
-            int registryPort = TestLibrary.getUnusedRandomPort();
-            Registry localRegistry =
-                LocateRegistry.createRegistry(registryPort);
+            Registry localRegistry = TestLibrary.createRegistryOnEphemeralPort();
+            int registryPort = TestLibrary.getRegistryPort(localRegistry);
             System.err.println("created local registry");
 
             localRegistry.bind(BINDING, obj);
--- a/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,7 +29,7 @@
  *
  * @library ../../testlibrary
  * @modules java.rmi/sun.rmi.registry
- *          java.rmi/sun.rmi.server
+ *          java.rmi/sun.rmi.server:+open
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
  * @build TestLibrary
--- a/jdk/test/java/rmi/server/useCustomRef/UseCustomRef.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/server/useCustomRef/UseCustomRef.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -86,7 +86,7 @@
 
             System.err.println("creating Registry...");
 
-            registry = TestLibrary.createRegistryOnUnusedPort();
+            registry = TestLibrary.createRegistryOnEphemeralPort();
             int port = TestLibrary.getRegistryPort(registry);
             /*
              * create object with custom ref and bind in registry
--- a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java	Wed Jul 05 22:32:06 2017 +0200
@@ -77,7 +77,7 @@
                 TestParams.defaultPolicy +
                 " --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED" +
                 " --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED" +
-                " --add-exports java.rmi/sun.rmi.transport=ALL-UNNAMED" +
+                " --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED" +
                 " --add-exports java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" +
                 " -Djava.rmi.dgc.leaseValue=500000" +
                 "  -Dsun.rmi.dgc.checkInterval=" +
--- a/jdk/test/java/security/SecureRandom/ApiTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/security/SecureRandom/ApiTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -195,10 +195,10 @@
             case "AES-128":
             case "AES-192":
             case "AES-256":
-                int algoStrength = Integer.parseInt(alg.replaceAll("AES-", ""));
-                int maxStrengthSupported = Cipher.getMaxAllowedKeyLength("AES");
-                if (strength > maxStrengthSupported
-                        || algoStrength > maxStrengthSupported) {
+                int algoStrength = Integer.parseInt(alg.substring("AES-".length()));
+                int maxAESStrength = Cipher.getMaxAllowedKeyLength("AES");
+                if (strength > algoStrength
+                        || algoStrength > maxAESStrength) {
                     error = false;
                 }
                 break;
--- a/jdk/test/java/security/modules/ModularTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/security/modules/ModularTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -164,7 +164,7 @@
         final Builder builder;
         if (moduleType == MODULE_TYPE.EXPLICIT) {
             System.out.format(" %nGenerating ModuleDescriptor object");
-            builder = new Builder(moduleName).exports(pkg);
+            builder = ModuleDescriptor.module(moduleName).exports(pkg);
             if (isService && serviceInterface != null && serviceImpl != null) {
                 builder.provides(serviceInterface, serviceImpl);
             } else {
--- a/jdk/test/java/security/testlibrary/Proc.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/security/testlibrary/Proc.java	Wed Jul 05 22:32:06 2017 +0200
@@ -257,7 +257,8 @@
 
         if (hasModules) {
             Stream.of(jdk.internal.misc.VM.getRuntimeArguments())
-                    .filter(arg -> arg.startsWith("--add-exports="))
+                    .filter(arg -> arg.startsWith("--add-exports=") ||
+                                   arg.startsWith("--add-opens="))
                     .forEach(cmd::add);
         }
 
--- a/jdk/test/java/time/TEST.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/time/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -4,3 +4,4 @@
 modules = jdk.localedata
 lib.dirs = ../../lib/testlibrary
 lib.build = jdk.testlibrary.RandomFactory
+modules = java.base/java.time:open java.base/java.time.chrono:open java.base/java.time.zone:open
--- a/jdk/test/java/util/ArrayList/ArrayManagement.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/ArrayList/ArrayManagement.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 8146568
  * @summary brittle white box test of internal array management
+ * @modules java.base/java.util:open
  * @run testng ArrayManagement
  */
 
--- a/jdk/test/java/util/ArrayList/IteratorMicroBenchmark.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/ArrayList/IteratorMicroBenchmark.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,21 +22,36 @@
  */
 
 /*
- * This is not a regression test, but a micro-benchmark.
- * Be patient; this runs for half an hour!
+ * @test
+ * @summary micro-benchmark correctness mode
+ * @run main IteratorMicroBenchmark iterations=1 size=8 warmup=0
+ */
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Spliterator;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+/**
+ * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
  *
- * I have run this as follows:
- *
- * for f in -client -server; do mergeBench dolphin . jr -dsa -da $f IteratorMicroBenchmark.java; done
- *
+ * To run this in micro-benchmark mode, simply run as a normal java program.
+ * Be patient; this program runs for a very long time.
+ * For faster runs, restrict execution using command line args.
  *
  * @author Martin Buchholz
  */
-
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.regex.Pattern;
-
 public class IteratorMicroBenchmark {
     abstract static class Job {
         private final String name;
@@ -45,17 +60,28 @@
         public abstract void work() throws Throwable;
     }
 
-    private static void collectAllGarbage() {
-        final java.util.concurrent.CountDownLatch drained
-            = new java.util.concurrent.CountDownLatch(1);
+    static double warmupSeconds;
+    static long warmupNanos;
+
+    // --------------- GC finalization infrastructure ---------------
+
+    /** No guarantees, but effective in practice. */
+    static void forceFullGc() {
+        CountDownLatch finalizeDone = new CountDownLatch(1);
+        WeakReference<?> ref = new WeakReference<Object>(new Object() {
+            protected void finalize() { finalizeDone.countDown(); }});
         try {
-            System.gc();        // enqueue finalizable objects
-            new Object() { protected void finalize() {
-                drained.countDown(); }};
-            System.gc();        // enqueue detector
-            drained.await();    // wait for finalizer queue to drain
-            System.gc();        // cleanup finalized objects
-        } catch (InterruptedException e) { throw new Error(e); }
+            for (int i = 0; i < 10; i++) {
+                System.gc();
+                if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
+                    System.runFinalization(); // try to pick up stragglers
+                    return;
+                }
+            }
+        } catch (InterruptedException unexpected) {
+            throw new AssertionError("unexpected InterruptedException");
+        }
+        throw new AssertionError("failed to do a \"full\" gc");
     }
 
     /**
@@ -65,23 +91,22 @@
      * Returns array of average times per job per run.
      */
     private static long[] time0(Job ... jobs) throws Throwable {
-        final long warmupNanos = 10L * 1000L * 1000L * 1000L;
         long[] nanoss = new long[jobs.length];
         for (int i = 0; i < jobs.length; i++) {
-            collectAllGarbage();
-            long t0 = System.nanoTime();
-            long t;
-            int j = 0;
-            do { jobs[i].work(); j++; }
-            while ((t = System.nanoTime() - t0) < warmupNanos);
-            nanoss[i] = t/j;
+            if (warmupNanos > 0) forceFullGc();
+            Job job = jobs[i];
+            long totalTime;
+            int runs = 0;
+            long startTime = System.nanoTime();
+            do { job.work(); runs++; }
+            while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
+            nanoss[i] = totalTime/runs;
         }
         return nanoss;
     }
 
     private static void time(Job ... jobs) throws Throwable {
-
-        long[] warmup = time0(jobs); // Warm up run
+        if (warmupSeconds > 0.0) time0(jobs); // Warm up run
         long[] nanoss = time0(jobs); // Real timing run
         long[] milliss = new long[jobs.length];
         double[] ratios = new double[jobs.length];
@@ -126,12 +151,17 @@
 
     private static int intArg(String[] args, String keyword, int defaultValue) {
         String val = keywordValue(args, keyword);
-        return val == null ? defaultValue : Integer.parseInt(val);
+        return (val == null) ? defaultValue : Integer.parseInt(val);
+    }
+
+    private static double doubleArg(String[] args, String keyword, double defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Double.parseDouble(val);
     }
 
     private static Pattern patternArg(String[] args, String keyword) {
         String val = keywordValue(args, keyword);
-        return val == null ? null : Pattern.compile(val);
+        return (val == null) ? null : Pattern.compile(val);
     }
 
     private static Job[] filter(Pattern filter, Job[] jobs) {
@@ -166,26 +196,33 @@
                     public void remove()     {        it.remove(); }};}};
     }
 
-    /**
-     * Usage: [iterations=N] [size=N] [filter=REGEXP]
-     */
     public static void main(String[] args) throws Throwable {
-        final int iterations = intArg(args, "iterations", 100000);
+        final int iterations = intArg(args, "iterations", 100_000);
         final int size       = intArg(args, "size", 1000);
+        warmupSeconds        = doubleArg(args, "warmup", 7.0);
         final Pattern filter = patternArg(args, "filter");
 
+        warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
+
+//         System.out.printf(
+//             "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
+//             iterations, size, warmupSeconds, filter);
+
         final ConcurrentSkipListMap<Integer,Integer> m
             = new ConcurrentSkipListMap<Integer,Integer>();
-        final Vector<Integer> v = new Vector<Integer>(size);
         final ArrayList<Integer> al = new ArrayList<Integer>(size);
 
         // Populate collections with random data
-        final Random rnd = new Random();
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
         for (int i = 0; i < size; i++) {
             m.put(rnd.nextInt(size), rnd.nextInt(size));
-            v.add(rnd.nextInt(size));
+            al.add(rnd.nextInt(size));
         }
-        al.addAll(v);
+        final Vector<Integer> v = new Vector<Integer>(al);
+        final ArrayDeque<Integer> ad = new ArrayDeque<Integer>(al);
+        // shuffle ArrayDeque elements so they wrap
+        for (int i = 0, n = rnd.nextInt(size); i < n; i++)
+            ad.addLast(ad.removeFirst());
 
         // Also test "short" collections
         final int shortSize = 5;
@@ -222,6 +259,15 @@
                         for (int j = 0; j < size; ++j)
                             sum += a[j];
                         check.sum(sum);}}},
+            new Job("descending array loop") {
+                public void work() throws Throwable {
+                    Integer[] a = al.toArray(new Integer[0]);
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        int size = a.length;
+                        for (int j = size - 1; j >= 0; j--)
+                            sum += a[j];
+                        check.sum(sum);}}},
             new Job("Vector get loop") {
                 public void work() throws Throwable {
                     for (int i = 0; i < iterations; i++) {
@@ -334,6 +380,13 @@
                         for (Integer n : al)
                             sum += n;
                         check.sum(sum);}}},
+            new Job("ArrayDeque iterate for loop") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        for (Integer n : ad)
+                            sum += n;
+                        check.sum(sum);}}},
             new Job("ArrayList descending listIterator loop") {
                 public void work() throws Throwable {
                     for (int i = 0; i < iterations; i++) {
@@ -350,6 +403,137 @@
                         while (it.hasNext())
                             sum += it.next();
                         check.sum(sum);}}},
+            new Job("ArrayDeque.descendingIterator() loop") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        Iterator<Integer> it = ad.descendingIterator();
+                        while (it.hasNext())
+                            sum += it.next();
+                        check.sum(sum);}}},
+            new Job("ArrayList.forEach") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.forEach(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.forEach") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.forEach(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("Vector.forEach") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.forEach(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.iterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.iterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.descendingIterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.descendingIterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.iterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.iterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("Vector.iterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.iterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.spliterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.spliterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.spliterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.spliterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("Vector.spliterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.spliterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.spliterator().tryAdvance()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        Spliterator<Integer> spliterator = al.spliterator();
+                        do {} while (spliterator.tryAdvance(n -> sum[0] += n));
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.spliterator().tryAdvance()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        Spliterator<Integer> spliterator = ad.spliterator();
+                        do {} while (spliterator.tryAdvance(n -> sum[0] += n));
+                        check.sum(sum[0]);}}},
+            new Job("Vector.spliterator().tryAdvance()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        Spliterator<Integer> spliterator = v.spliterator();
+                        do {} while (spliterator.tryAdvance(n -> sum[0] += n));
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
+            new Job("Vector.removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList subList .removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    List<Integer> sl = asSubList(al);
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        sl.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
             new Job("ArrayList subList get loop") {
                 public void work() throws Throwable {
                     List<Integer> sl = asSubList(al);
@@ -442,7 +626,61 @@
                         int sum = 0;
                         for (Map.Entry<Integer,Integer> e : m.entrySet())
                             sum += e.getKey();
-                        deoptimize(sum);}}}
+                        deoptimize(sum);}}},
+            new Job("ArrayList.toArray()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Object o : al.toArray())
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.toArray(a)") {
+                public void work() throws Throwable {
+                    Integer[] a = new Integer[size];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.toArray(a);
+                        for (Object o : a)
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.toArray()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Object o : ad.toArray())
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.toArray(a)") {
+                public void work() throws Throwable {
+                    Integer[] a = new Integer[size];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.toArray(a);
+                        for (Object o : a)
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("Vector.toArray()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Object o : v.toArray())
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("Vector.toArray(a)") {
+                public void work() throws Throwable {
+                    Integer[] a = new Integer[size];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.toArray(a);
+                        for (Object o : a)
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
         };
 
         time(filter(filter, jobs));
--- a/jdk/test/java/util/Calendar/StampOverflow.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Calendar/StampOverflow.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug 4404619 6348819
  * @summary Make sure that Calendar doesn't cause nextStamp overflow.
+ * @modules java.base/java.util:open
  */
 
 import java.lang.reflect.*;
--- a/jdk/test/java/util/Collection/CollectionDefaults.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Collection/CollectionDefaults.java	Wed Jul 05 22:32:06 2017 +0200
@@ -60,9 +60,19 @@
     public static final Predicate<Integer> pEven = x -> 0 == x % 2;
     public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
 
+    private static final int SIZE = 100;
+
     private static final List<Function<Collection<Integer>, Collection<Integer>>> TEST_SUPPLIERS = Arrays.asList(
             // Collection
             ExtendsAbstractCollection<Integer>::new,
+            java.util.ArrayDeque<Integer>::new,
+            java.util.concurrent.ConcurrentLinkedDeque<Integer>::new,
+            java.util.concurrent.ConcurrentLinkedQueue<Integer>::new,
+            java.util.concurrent.LinkedBlockingDeque<Integer>::new,
+            java.util.concurrent.LinkedBlockingQueue<Integer>::new,
+            java.util.concurrent.LinkedTransferQueue<Integer>::new,
+            (coll) -> new java.util.concurrent.ArrayBlockingQueue<Integer>(
+                3 * SIZE, false, coll),
 
             // Lists
             java.util.ArrayList<Integer>::new,
@@ -80,8 +90,6 @@
             ExtendsAbstractSet<Integer>::new
        );
 
-    private static final int SIZE = 100;
-
     @DataProvider(name="setProvider", parallel=true)
     public static Iterator<Object[]> setCases() {
         final List<Object[]> cases = new LinkedList<>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/IteratorMicroBenchmark.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,404 @@
+/*
+ * 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
+ * @summary micro-benchmark correctness mode
+ * @run main IteratorMicroBenchmark iterations=1 size=8 warmup=0
+ */
+
+import static java.util.stream.Collectors.summingInt;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Spliterator;
+import java.util.Vector;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+/**
+ * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
+ *
+ * To run this in micro-benchmark mode, simply run as a normal java program.
+ * Be patient; this program runs for a very long time.
+ * For faster runs, restrict execution using command line args.
+ *
+ * This is an interface based version of ArrayList/IteratorMicroBenchmark
+ *
+ * @author Martin Buchholz
+ */
+public class IteratorMicroBenchmark {
+    abstract static class Job {
+        private final String name;
+        public Job(String name) { this.name = name; }
+        public String name() { return name; }
+        public abstract void work() throws Throwable;
+    }
+
+    final int iterations;
+    final int size;             // number of elements in collections
+    final double warmupSeconds;
+    final long warmupNanos;
+    final Pattern filter;       // select subset of Jobs to run
+    final boolean reverse;      // reverse order of Jobs
+    final boolean shuffle;      // randomize order of Jobs
+
+    IteratorMicroBenchmark(String[] args) {
+        iterations    = intArg(args, "iterations", 10_000);
+        size          = intArg(args, "size", 1000);
+        warmupSeconds = doubleArg(args, "warmup", 7.0);
+        filter        = patternArg(args, "filter");
+        reverse       = booleanArg(args, "reverse");
+        shuffle       = booleanArg(args, "shuffle");
+
+        warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
+    }
+
+    // --------------- GC finalization infrastructure ---------------
+
+    /** No guarantees, but effective in practice. */
+    static void forceFullGc() {
+        CountDownLatch finalizeDone = new CountDownLatch(1);
+        WeakReference<?> ref = new WeakReference<Object>(new Object() {
+            protected void finalize() { finalizeDone.countDown(); }});
+        try {
+            for (int i = 0; i < 10; i++) {
+                System.gc();
+                if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
+                    System.runFinalization(); // try to pick up stragglers
+                    return;
+                }
+            }
+        } catch (InterruptedException unexpected) {
+            throw new AssertionError("unexpected InterruptedException");
+        }
+        throw new AssertionError("failed to do a \"full\" gc");
+    }
+
+    /**
+     * Runs each job for long enough that all the runtime compilers
+     * have had plenty of time to warm up, i.e. get around to
+     * compiling everything worth compiling.
+     * Returns array of average times per job per run.
+     */
+    long[] time0(List<Job> jobs) throws Throwable {
+        final int size = jobs.size();
+        long[] nanoss = new long[size];
+        for (int i = 0; i < size; i++) {
+            if (warmupNanos > 0) forceFullGc();
+            Job job = jobs.get(i);
+            long totalTime;
+            int runs = 0;
+            long startTime = System.nanoTime();
+            do { job.work(); runs++; }
+            while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
+            nanoss[i] = totalTime/runs;
+        }
+        return nanoss;
+    }
+
+    void time(List<Job> jobs) throws Throwable {
+        if (warmupNanos > 0) time0(jobs); // Warm up run
+        final int size = jobs.size();
+        final long[] nanoss = time0(jobs); // Real timing run
+        final long[] milliss = new long[size];
+        final double[] ratios = new double[size];
+
+        final String nameHeader   = "Method";
+        final String millisHeader = "Millis";
+        final String ratioHeader  = "Ratio";
+
+        int nameWidth   = nameHeader.length();
+        int millisWidth = millisHeader.length();
+        int ratioWidth  = ratioHeader.length();
+
+        for (int i = 0; i < size; i++) {
+            nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
+
+            milliss[i] = nanoss[i]/(1000L * 1000L);
+            millisWidth = Math.max(millisWidth,
+                                   String.format("%d", milliss[i]).length());
+
+            ratios[i] = (double) nanoss[i] / (double) nanoss[0];
+            ratioWidth = Math.max(ratioWidth,
+                                  String.format("%.3f", ratios[i]).length());
+        }
+
+        String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
+                                      nameWidth, millisWidth, ratioWidth);
+        String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
+                                            nameWidth, millisWidth, ratioWidth);
+        System.out.printf(headerFormat, "Method", "Millis", "Ratio");
+
+        // Print out absolute and relative times, calibrated against first job
+        for (int i = 0; i < size; i++)
+            System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
+    }
+
+    private static String keywordValue(String[] args, String keyword) {
+        for (String arg : args)
+            if (arg.startsWith(keyword))
+                return arg.substring(keyword.length() + 1);
+        return null;
+    }
+
+    private static int intArg(String[] args, String keyword, int defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Integer.parseInt(val);
+    }
+
+    private static double doubleArg(String[] args, String keyword, double defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Double.parseDouble(val);
+    }
+
+    private static Pattern patternArg(String[] args, String keyword) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? null : Pattern.compile(val);
+    }
+
+    private static boolean booleanArg(String[] args, String keyword) {
+        String val = keywordValue(args, keyword);
+        if (val == null || val.equals("false")) return false;
+        if (val.equals("true")) return true;
+        throw new IllegalArgumentException(val);
+    }
+
+    private static List<Job> filter(Pattern filter, List<Job> jobs) {
+        if (filter == null) return jobs;
+        ArrayList<Job> newJobs = new ArrayList<>();
+        for (Job job : jobs)
+            if (filter.matcher(job.name()).find())
+                newJobs.add(job);
+        return newJobs;
+    }
+
+    private static void deoptimize(int sum) {
+        if (sum == 42)
+            System.out.println("the answer");
+    }
+
+    private static <T> List<T> asSubList(List<T> list) {
+        return list.subList(0, list.size());
+    }
+
+    private static <T> Iterable<T> backwards(final List<T> list) {
+        return new Iterable<T>() {
+            public Iterator<T> iterator() {
+                return new Iterator<T>() {
+                    final ListIterator<T> it = list.listIterator(list.size());
+                    public boolean hasNext() { return it.hasPrevious(); }
+                    public T next()          { return it.previous(); }
+                    public void remove()     {        it.remove(); }};}};
+    }
+
+    // Checks for correctness *and* prevents loop optimizations
+    class Check {
+        private int sum;
+        public void sum(int sum) {
+            if (this.sum == 0)
+                this.sum = sum;
+            if (this.sum != sum)
+                throw new AssertionError("Sum mismatch");
+        }
+    }
+    volatile Check check = new Check();
+
+    public static void main(String[] args) throws Throwable {
+        new IteratorMicroBenchmark(args).run();
+    }
+
+    void run() throws Throwable {
+//         System.out.printf(
+//             "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
+//             iterations, size, warmupSeconds, filter);
+
+        final ArrayList<Integer> al = new ArrayList<Integer>(size);
+
+        // Populate collections with random data
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        for (int i = 0; i < size; i++)
+            al.add(rnd.nextInt(size));
+
+        final ArrayDeque<Integer> ad = new ArrayDeque<>(al);
+        final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<>(al.size());
+        abq.addAll(al);
+
+        // shuffle circular array elements so they wrap
+        for (int i = 0, n = rnd.nextInt(size); i < n; i++) {
+            ad.addLast(ad.removeFirst());
+            abq.add(abq.remove());
+        }
+
+        ArrayList<Job> jobs = new ArrayList<>(Arrays.asList());
+
+        List.of(al, ad, abq,
+                new LinkedList<>(al),
+                new PriorityQueue<>(al),
+                new Vector<>(al),
+                new ConcurrentLinkedQueue<>(al),
+                new ConcurrentLinkedDeque<>(al),
+                new LinkedBlockingQueue<>(al),
+                new LinkedBlockingDeque<>(al),
+                new LinkedTransferQueue<>(al),
+                new PriorityBlockingQueue<>(al))
+            .stream()
+            .forEach(x -> {
+                         jobs.addAll(collectionJobs(x));
+                         if (x instanceof Deque)
+                             jobs.addAll(dequeJobs((Deque<Integer>)x));
+                     });
+
+        if (reverse) Collections.reverse(jobs);
+        if (shuffle) Collections.shuffle(jobs);
+
+        time(filter(filter, jobs));
+    }
+
+    List<Job> collectionJobs(Collection<Integer> x) {
+        String klazz = x.getClass().getSimpleName();
+        return List.of(
+            new Job(klazz + " iterate for loop") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        for (Integer n : x)
+                            sum += n;
+                        check.sum(sum);}}},
+            new Job(klazz + " .iterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.iterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .spliterator().tryAdvance()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        Spliterator<Integer> spliterator = x.spliterator();
+                        do {} while (spliterator.tryAdvance(n -> sum[0] += n));
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .spliterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.spliterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .forEach") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.forEach(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .toArray()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Object o : x.toArray())
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .toArray(a)") {
+                public void work() throws Throwable {
+                    Integer[] a = new Integer[x.size()];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.toArray(a);
+                        for (Object o : a)
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .toArray(empty)") {
+                public void work() throws Throwable {
+                    Integer[] empty = new Integer[0];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Integer o : x.toArray(empty))
+                            sum[0] += o;
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .stream().collect") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        check.sum(x.stream()
+                                  .collect(summingInt(e -> e)));}}},
+            new Job(klazz + " .parallelStream().collect") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        check.sum(x.parallelStream()
+                                  .collect(summingInt(e -> e)));}}});
+    }
+
+    List<Job> dequeJobs(Deque<Integer> x) {
+        String klazz = x.getClass().getSimpleName();
+        return List.of(
+            new Job(klazz + " .descendingIterator() loop") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        Iterator<Integer> it = x.descendingIterator();
+                        while (it.hasNext())
+                            sum += it.next();
+                        check.sum(sum);}}},
+            new Job(klazz + " .descendingIterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.descendingIterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}});
+    }
+}
--- a/jdk/test/java/util/Collection/MOAT.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Collection/MOAT.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
  *          4802647 7123424 8024709
  * @summary Run many tests on many Collection and Map implementations
  * @author  Martin Buchholz
+ * @modules java.base/java.util:open
  * @run main MOAT
  * @key randomness
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/RemoveMicroBenchmark.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,504 @@
+/*
+ * 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
+ * @summary micro-benchmark correctness mode
+ * @run main RemoveMicroBenchmark iterations=1 size=8 warmup=0
+ */
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Vector;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+import java.util.function.Supplier;
+
+/**
+ * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
+ *
+ * To run this in micro-benchmark mode, simply run as a normal java program.
+ * Be patient; this program runs for a very long time.
+ * For faster runs, restrict execution using command line args.
+ *
+ * @author Martin Buchholz
+ */
+public class RemoveMicroBenchmark {
+    abstract static class Job {
+        private final String name;
+        public Job(String name) { this.name = name; }
+        public String name() { return name; }
+        public abstract void work() throws Throwable;
+    }
+
+    final int iterations;
+    final int size;             // number of elements in collections
+    final double warmupSeconds;
+    final long warmupNanos;
+    final Pattern filter;       // select subset of Jobs to run
+    final boolean reverse;      // reverse order of Jobs
+    final boolean shuffle;      // randomize order of Jobs
+
+    RemoveMicroBenchmark(String[] args) {
+        iterations    = intArg(args, "iterations", 10_000);
+        size          = intArg(args, "size", 1000);
+        warmupSeconds = doubleArg(args, "warmup", 7.0);
+        filter        = patternArg(args, "filter");
+        reverse       = booleanArg(args, "reverse");
+        shuffle       = booleanArg(args, "shuffle");
+
+        warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
+    }
+
+    // --------------- GC finalization infrastructure ---------------
+
+    /** No guarantees, but effective in practice. */
+    static void forceFullGc() {
+        CountDownLatch finalizeDone = new CountDownLatch(1);
+        WeakReference<?> ref = new WeakReference<Object>(new Object() {
+            protected void finalize() { finalizeDone.countDown(); }});
+        try {
+            for (int i = 0; i < 10; i++) {
+                System.gc();
+                if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
+                    System.runFinalization(); // try to pick up stragglers
+                    return;
+                }
+            }
+        } catch (InterruptedException unexpected) {
+            throw new AssertionError("unexpected InterruptedException");
+        }
+        throw new AssertionError("failed to do a \"full\" gc");
+    }
+
+    /**
+     * Runs each job for long enough that all the runtime compilers
+     * have had plenty of time to warm up, i.e. get around to
+     * compiling everything worth compiling.
+     * Returns array of average times per job per run.
+     */
+    long[] time0(List<Job> jobs) throws Throwable {
+        final int size = jobs.size();
+        long[] nanoss = new long[size];
+        for (int i = 0; i < size; i++) {
+            if (warmupNanos > 0) forceFullGc();
+            Job job = jobs.get(i);
+            long totalTime;
+            int runs = 0;
+            long startTime = System.nanoTime();
+            do { job.work(); runs++; }
+            while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
+            nanoss[i] = totalTime/runs;
+        }
+        return nanoss;
+    }
+
+    void time(List<Job> jobs) throws Throwable {
+        if (warmupNanos > 0) time0(jobs); // Warm up run
+        final int size = jobs.size();
+        final long[] nanoss = time0(jobs); // Real timing run
+        final long[] milliss = new long[size];
+        final double[] ratios = new double[size];
+
+        final String nameHeader   = "Method";
+        final String millisHeader = "Millis";
+        final String ratioHeader  = "Ratio";
+
+        int nameWidth   = nameHeader.length();
+        int millisWidth = millisHeader.length();
+        int ratioWidth  = ratioHeader.length();
+
+        for (int i = 0; i < size; i++) {
+            nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
+
+            milliss[i] = nanoss[i]/(1000L * 1000L);
+            millisWidth = Math.max(millisWidth,
+                                   String.format("%d", milliss[i]).length());
+
+            ratios[i] = (double) nanoss[i] / (double) nanoss[0];
+            ratioWidth = Math.max(ratioWidth,
+                                  String.format("%.3f", ratios[i]).length());
+        }
+
+        String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
+                                      nameWidth, millisWidth, ratioWidth);
+        String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
+                                            nameWidth, millisWidth, ratioWidth);
+        System.out.printf(headerFormat, "Method", "Millis", "Ratio");
+
+        // Print out absolute and relative times, calibrated against first job
+        for (int i = 0; i < size; i++)
+            System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
+    }
+
+    private static String keywordValue(String[] args, String keyword) {
+        for (String arg : args)
+            if (arg.startsWith(keyword))
+                return arg.substring(keyword.length() + 1);
+        return null;
+    }
+
+    private static int intArg(String[] args, String keyword, int defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Integer.parseInt(val);
+    }
+
+    private static double doubleArg(String[] args, String keyword, double defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Double.parseDouble(val);
+    }
+
+    private static Pattern patternArg(String[] args, String keyword) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? null : Pattern.compile(val);
+    }
+
+    private static boolean booleanArg(String[] args, String keyword) {
+        String val = keywordValue(args, keyword);
+        if (val == null || val.equals("false")) return false;
+        if (val.equals("true")) return true;
+        throw new IllegalArgumentException(val);
+    }
+
+    private static List<Job> filter(Pattern filter, List<Job> jobs) {
+        if (filter == null) return jobs;
+        ArrayList<Job> newJobs = new ArrayList<>();
+        for (Job job : jobs)
+            if (filter.matcher(job.name()).find())
+                newJobs.add(job);
+        return newJobs;
+    }
+
+    private static void deoptimize(int sum) {
+        if (sum == 42)
+            System.out.println("the answer");
+    }
+
+    private static <T> List<T> asSubList(List<T> list) {
+        return list.subList(0, list.size());
+    }
+
+    private static <T> Iterable<T> backwards(final List<T> list) {
+        return new Iterable<T>() {
+            public Iterator<T> iterator() {
+                return new Iterator<T>() {
+                    final ListIterator<T> it = list.listIterator(list.size());
+                    public boolean hasNext() { return it.hasPrevious(); }
+                    public T next()          { return it.previous(); }
+                    public void remove()     {        it.remove(); }};}};
+    }
+
+    // Checks for correctness *and* prevents loop optimizations
+    class Check {
+        private int sum;
+        public void sum(int sum) {
+            if (this.sum == 0)
+                this.sum = sum;
+            if (this.sum != sum)
+                throw new AssertionError("Sum mismatch");
+        }
+    }
+    volatile Check check = new Check();
+
+    public static void main(String[] args) throws Throwable {
+        new RemoveMicroBenchmark(args).run();
+    }
+
+    void run() throws Throwable {
+//         System.out.printf(
+//             "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
+//             iterations, size, warmupSeconds, filter);
+
+        final ArrayList<Integer> al = new ArrayList<Integer>(size);
+
+        // Populate collections with random data
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        for (int i = 0; i < size; i++)
+            al.add(rnd.nextInt(size));
+
+        ArrayList<Job> jobs = new ArrayList<>();
+
+        List.<Collection<Integer>>of(
+            new ArrayList<>(),
+            new LinkedList<>(),
+            new Vector<>(),
+            new ArrayDeque<>(),
+            new PriorityQueue<>(),
+            new ArrayBlockingQueue<>(al.size()),
+            new ConcurrentLinkedQueue<>(),
+            new ConcurrentLinkedDeque<>(),
+            new LinkedBlockingQueue<>(),
+            new LinkedBlockingDeque<>(),
+            new LinkedTransferQueue<>(),
+            new PriorityBlockingQueue<>())
+            .stream().forEach(
+                x -> {
+                    String klazz = x.getClass().getSimpleName();
+                    jobs.addAll(collectionJobs(klazz, () -> x, al));
+                    if (x instanceof Queue) {
+                        Queue<Integer> queue = (Queue<Integer>) x;
+                        jobs.addAll(queueJobs(klazz, () -> queue, al));
+                    }
+                    if (x instanceof Deque) {
+                        Deque<Integer> deque = (Deque<Integer>) x;
+                        jobs.addAll(dequeJobs(klazz, () -> deque, al));
+                    }
+                    if (x instanceof BlockingQueue) {
+                        BlockingQueue<Integer> q = (BlockingQueue<Integer>) x;
+                        jobs.addAll(blockingQueueJobs(klazz, () -> q, al));
+                    }
+                    if (x instanceof BlockingDeque) {
+                        BlockingDeque<Integer> q = (BlockingDeque<Integer>) x;
+                        jobs.addAll(blockingDequeJobs(klazz, () -> q, al));
+                    }
+                    if (x instanceof List) {
+                        List<Integer> list = (List<Integer>) x;
+                        jobs.addAll(
+                            collectionJobs(
+                                klazz + " subList",
+                                () -> list.subList(0, x.size()),
+                                al));
+                    }
+                });
+
+        if (reverse) Collections.reverse(jobs);
+        if (shuffle) Collections.shuffle(jobs);
+
+        time(filter(filter, jobs));
+    }
+
+    Collection<Integer> universeRecorder(int[] sum) {
+        return new ArrayList<>() {
+            public boolean contains(Object x) {
+                sum[0] += (Integer) x;
+                return true;
+            }};
+    }
+
+    Collection<Integer> emptyRecorder(int[] sum) {
+        return new ArrayList<>() {
+            public boolean contains(Object x) {
+                sum[0] += (Integer) x;
+                return false;
+            }};
+    }
+
+    List<Job> collectionJobs(
+        String description,
+        Supplier<Collection<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " .removeIf") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        x.removeIf(n -> { sum[0] += n; return true; });
+                        check.sum(sum[0]);}}},
+            new Job(description + " .removeAll") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    Collection<Integer> universe = universeRecorder(sum);
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        x.removeAll(universe);
+                        check.sum(sum[0]);}}},
+            new Job(description + " .retainAll") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    Collection<Integer> empty = emptyRecorder(sum);
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        x.retainAll(empty);
+                        check.sum(sum[0]);}}},
+            new Job(description + " Iterator.remove") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        Iterator<Integer> it = x.iterator();
+                        while (it.hasNext()) {
+                            sum[0] += it.next();
+                            it.remove();
+                        }
+                        check.sum(sum[0]);}}},
+            new Job(description + " clear") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        x.forEach(e -> sum[0] += e);
+                        x.clear();
+                        check.sum(sum[0]);}}});
+    }
+
+    List<Job> queueJobs(
+        String description,
+        Supplier<Queue<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " poll()") {
+                public void work() throws Throwable {
+                    Queue<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.poll()) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}});
+    }
+
+    List<Job> dequeJobs(
+        String description,
+        Supplier<Deque<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " descendingIterator().remove") {
+                public void work() throws Throwable {
+                    Deque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        Iterator<Integer> it = x.descendingIterator();
+                        while (it.hasNext()) {
+                            sum[0] += it.next();
+                            it.remove();
+                        }
+                        check.sum(sum[0]);}}},
+            new Job(description + " pollFirst()") {
+                public void work() throws Throwable {
+                    Deque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.pollFirst()) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}},
+            new Job(description + " pollLast()") {
+                public void work() throws Throwable {
+                    Deque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.pollLast()) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}});
+    }
+
+    List<Job> blockingQueueJobs(
+        String description,
+        Supplier<BlockingQueue<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " drainTo(sink)") {
+                public void work() throws Throwable {
+                    BlockingQueue<Integer> x = supplier.get();
+                    ArrayList<Integer> sink = new ArrayList<>();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        sink.clear();
+                        x.addAll(al);
+                        x.drainTo(sink);
+                        sink.forEach(e -> sum[0] += e);
+                        check.sum(sum[0]);}}},
+            new Job(description + " drainTo(sink, n)") {
+                public void work() throws Throwable {
+                    BlockingQueue<Integer> x = supplier.get();
+                    ArrayList<Integer> sink = new ArrayList<>();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        sink.clear();
+                        x.addAll(al);
+                        x.drainTo(sink, al.size());
+                        sink.forEach(e -> sum[0] += e);
+                        check.sum(sum[0]);}}});
+    }
+
+    List<Job> blockingDequeJobs(
+        String description,
+        Supplier<BlockingDeque<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " timed pollFirst()") {
+                public void work() throws Throwable {
+                    BlockingDeque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.pollFirst(0L, TimeUnit.DAYS)) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}},
+            new Job(description + " timed pollLast()") {
+                public void work() throws Throwable {
+                    BlockingDeque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.pollLast(0L, TimeUnit.DAYS)) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}});
+    }
+}
--- a/jdk/test/java/util/Collections/SyncSubMutexes.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Collections/SyncSubMutexes.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
  * @bug 8048209
  * @summary Check that Collections.synchronizedNavigableSet().tailSet() is using
  * the same lock object as it's source.
+ * @modules java.base/java.util:open
  * @run testng SyncSubMutexes
  */
 import java.lang.reflect.Field;
--- a/jdk/test/java/util/Currency/CurrencyTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Currency/CurrencyTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,8 @@
  * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531
  *    6488442 7036905 8008577 8039317 8074350 8074351 8150324
  * @summary Basic tests for Currency class.
- * @modules jdk.localedata
+ * @modules java.base/java.util:open
+ *          jdk.localedata
  */
 
 import java.io.ByteArrayInputStream;
--- a/jdk/test/java/util/Currency/ValidateISO4217.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Currency/ValidateISO4217.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,8 @@
  * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759
  *      8039317 8074350 8074351 8145952
  * @summary Validate ISO 4217 data for Currency class.
+ * @modules java.base/java.util:open
+ *          jdk.localedata
  */
 
 /*
--- a/jdk/test/java/util/EnumSet/OneUniverse.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/EnumSet/OneUniverse.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @test
  * @bug     6276988
  * @summary All enum constants in a class should share a single "universe".
+ * @modules java.base/java.util:open
  */
 
 import java.lang.reflect.Field;
--- a/jdk/test/java/util/Hashtable/DeserializedLength.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Hashtable/DeserializedLength.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
  * @test
  * @bug 8068427
  * @summary Hashtable deserialization reconstitutes table with wrong capacity
+ * @modules java.base/java.util:open
  */
 public class DeserializedLength {
 
--- a/jdk/test/java/util/IdentityHashMap/Capacity.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/IdentityHashMap/Capacity.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,6 +38,7 @@
  * @bug 6904367
  * @summary IdentityHashMap reallocates storage when inserting expected
  *          number of elements
+ * @modules java.base/java.util:open
  * @run testng Capacity
  * @key randomness
  */
--- a/jdk/test/java/util/Locale/bug6312358.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Locale/bug6312358.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
  * @bug 6312358
  * @summary Verify that an NPE is thrown by issueing Locale.getInstance() with
  *      any argument being null.
+ * @modules java.base/java.util:open
  */
 
 import java.lang.reflect.InvocationTargetException;
--- a/jdk/test/java/util/ResourceBundle/ReferencesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/ResourceBundle/ReferencesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,7 @@
 /*
  * @test
  * @bug 4405807
+ * @modules java.base/java.util:open
  * @run main/othervm -Xms10m ReferencesTest
  * @summary Verify that references from ResourceBundle cache don't prevent
  * class loader reclamation.
--- a/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -71,7 +71,8 @@
 echo 'jdk.test.Main should load bundles local to named module "test".'
 $JAVA -p mods -m test/jdk.test.Main de fr ja zh-tw en de || STATUS=1
 
-echo "jdk.test.Main should NOT load bundles from the jar file specified by the class-path."
-$JAVA -cp extra.jar -p mods -m test/jdk.test.Main vi && STATUS=1
+echo "jdk.test.Main should load bundles from the jar file specified by the class-path."
+$JAVA -cp extra.jar -p mods -m test/jdk.test.Main vi || STATUS=1
+
 
 exit $STATUS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int errors = 0;
+        for (String loctag : args) {
+            Locale locale = Locale.forLanguageTag(loctag);
+            if (locale.equals(Locale.ROOT)) {
+                continue;
+            }
+            ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources",
+                                                         locale);
+            String tag = locale.toLanguageTag(); // normalized
+            String value = rb.getString("key");
+            System.out.println(rb.getBaseBundleName() + ": locale = " + tag + ", value = " + value);
+            if (!value.startsWith(tag + ':')) {
+                System.out.println("ERROR: " + value + " expected: " + tag);
+                errors++;
+            }
+
+            // inaccessible bundles
+            try {
+                ResourceBundle.getBundle("jdk.test.internal.resources.Foo", locale);
+                System.out.println("ERROR: jdk.test.internal.resources.Foo should not be accessible");
+                errors++;
+            } catch (MissingResourceException e) {
+                e.printStackTrace();
+
+                Throwable cause = e.getCause();
+                System.out.println("Expected: " +
+                    (cause != null ? cause.getMessage() : e.getMessage()));
+            }
+        }
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.test.internal.resources;
+
+import java.util.ListResourceBundle;
+
+public class Foo extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_de.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.test.internal.resources;
+
+import java.util.ListResourceBundle;
+
+public class Foo_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_en.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.test.internal.resources;
+
+import java.util.ListResourceBundle;
+
+public class Foo_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_fr.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.test.internal.resources;
+
+import java.util.ListResourceBundle;
+
+public class Foo_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_ja.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh_TW.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_de.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_en.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_fr.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.test.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_ja.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh_TW.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+module bundles {
+    opens jdk.test.resources;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/unnamed.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,74 @@
+#
+# 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 Test unnamed module to find resource bundles exported
+#          from a named module 
+
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAVA="$TESTJAVA/bin/java"
+
+rm -rf mods
+
+mkdir -p mods/test
+
+B=bundles
+mkdir -p mods/$B
+CLASSES="`find $TESTSRC/src/$B -name '*.java'`"
+if [ "x$CLASSES" != x ]; then
+    $JAVAC -g -d mods --module-source-path $TESTSRC/src $CLASSES
+fi
+PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`"
+if [ "x$PROPS" != x ]; then
+    for P in $PROPS
+    do
+      D=`dirname $P`
+      mkdir -p mods/$B/$D
+      cp $TESTSRC/src/$B/$P mods/$B/$D/
+    done
+fi
+
+mkdir classes
+$JAVAC -d classes $TESTSRC/Main.java
+
+# access resource bundles that are exported private unconditionally
+$JAVA -cp classes --module-path mods --add-modules bundles \
+      Main de fr ja zh-tw en de
+
+# --add-exports can't open resources 
+$JAVA -cp classes --module-path mods --add-modules bundles \
+      --add-opens bundles/jdk.test.internal.resources=ALL-UNNAMED \
+      Main de fr ja zh-tw en de
+
+exit $?
--- a/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -111,9 +111,9 @@
 runJava -cp mods/named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \
     jdk.test.resources.props.MyResources true
 runJava -cp mods/named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \
-    jdk.test.resources.classes.MyResources false
+    jdk.test.resources.classes.MyResources true
 runJava -cp mods/named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \
-    jdk.test.resources.props.MyResources false
+    jdk.test.resources.props.MyResources true
 
 # Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg
 # both of which specify an unnamed module with ResourceBundle.getBundle.
@@ -171,13 +171,13 @@
 
 # Add mods/exported.named.bundles to the class path.
 runJava -cp mods/exported.named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \
-    jdk.test.resources.exported.classes.MyResources false
+    jdk.test.resources.exported.classes.MyResources true
 runJava -cp mods/exported.named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \
-    jdk.test.resources.exported.props.MyResources false
+    jdk.test.resources.exported.props.MyResources true
 runJava -cp mods/exported.named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \
-    jdk.test.resources.exported.classes.MyResources false
+    jdk.test.resources.exported.classes.MyResources true
 runJava -cp mods/exported.named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \
-    jdk.test.resources.exported.props.MyResources false
+    jdk.test.resources.exported.props.MyResources true
 
 # Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg
 # which specify an unnamed module with ResourceBundle.getBundle.
--- a/jdk/test/java/util/ServiceLoader/Basic.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-//
-
-import java.io.*;
-import java.util.*;
-
-
-public class Basic {
-
-    private static PrintStream out = System.err;
-
-    private static <T> Set<T> setOf(Iterable<T> it) {
-        Set<T> s = new HashSet<T>();
-        for (T t : it)
-            s.add(t);
-        return s;
-    }
-
-    private static <T> void checkEquals(Set<T> s1, Set<T> s2, boolean eq) {
-        if (s1.equals(s2) != eq)
-            throw new RuntimeException(String.format("%b %s : %s",
-                                                     eq, s1, s2));
-    }
-
-    abstract static class TestLoader {
-        String name;
-
-        TestLoader(String name) { this.name = name; }
-
-        abstract ServiceLoader<FooService> load();
-    }
-
-    static TestLoader tcclLoader = new TestLoader("Thread context class loader") {
-        ServiceLoader<FooService> load() {
-            return ServiceLoader.load(FooService.class);
-        }
-    };
-
-    static TestLoader systemClLoader = new TestLoader("System class loader") {
-        ServiceLoader<FooService> load() {
-            return ServiceLoader.load(FooService.class, ClassLoader.getSystemClassLoader());
-        }
-    };
-
-    static TestLoader nullClLoader = new TestLoader("null (defer to system class loader)") {
-        ServiceLoader<FooService> load() {
-            return ServiceLoader.load(FooService.class, null);
-        }
-    };
-
-    public static void main(String[] args) {
-        for (TestLoader tl : Arrays.asList(tcclLoader, systemClLoader, nullClLoader)) {
-            test(tl);
-        }
-    }
-
-    static void test(TestLoader tl) {
-        ServiceLoader<FooService> sl = tl.load();
-        out.format("%s: %s%n", tl.name, sl);
-
-        // Providers are cached
-        Set<FooService> ps = setOf(sl);
-        checkEquals(ps, setOf(sl), true);
-
-        // The cache can be flushed and reloaded
-        sl.reload();
-        checkEquals(ps, setOf(sl), false);
-
-    }
-}
--- a/jdk/test/java/util/ServiceLoader/FooProvider1.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 FooProvider1 extends FooService { }
--- a/jdk/test/java/util/ServiceLoader/FooProvider2.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 FooProvider2 extends FooService { }
--- a/jdk/test/java/util/ServiceLoader/FooProvider3.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 FooProvider3 extends FooService { }
--- a/jdk/test/java/util/ServiceLoader/FooService.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 abstract class FooService { }
--- a/jdk/test/java/util/ServiceLoader/Load.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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.*;
-import java.util.*;
-
-
-public class Load {
-
-    private static PrintStream out = System.err;
-
-    public static void main(String[] args) throws Exception {
-
-        boolean installedOnly = false;
-
-        List<String> expected = new ArrayList<String>(Arrays.asList(args));
-        if (!expected.isEmpty() && expected.get(0).equals("-i")) {
-            expected.remove(0);
-            installedOnly = true;
-        }
-        if (expected.isEmpty())
-            throw new Exception("usage: Load [-i] ( fail | provider-class-name )*");
-
-        ServiceLoader<FooService> sl = (installedOnly
-                                        ? ServiceLoader.loadInstalled(FooService.class)
-                                        : ServiceLoader.load(FooService.class));
-        out.format("%s%n", sl);
-        Iterator<FooService> sli = sl.iterator();
-        Iterator<String> ei = expected.iterator();
-
-        for (;; ei.remove()) {
-            FooService fp = null;
-            try {
-                if (!sli.hasNext())
-                    break;
-                fp = sli.next();
-            } catch (ServiceConfigurationError x) {
-                if (ei.next().equals("fail")) {
-                    out.format("Failed as expected: %s%n", x);
-                    continue;
-                }
-                throw x;
-            }
-            String ec = ei.next();
-            if (!fp.getClass().getName().equals(ec))
-                throw new
-                    Exception(String.format("Wrong provider %s; expected %s",
-                                            fp.getClass().getName(), ec));
-            out.format("Provider found: %s%n", fp.getClass().getName());
-        }
-
-        if (ei.hasNext())
-            throw new Exception("Missing providers: " + expected);
-
-    }
-
-}
--- a/jdk/test/java/util/ServiceLoader/basic.sh	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-#
-# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# 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 4640520 6354623 7198496
-# @summary Unit test for java.util.ServiceLoader
-#
-# @build Basic Load FooService FooProvider1 FooProvider2 FooProvider3
-# @run shell basic.sh
-
-# Command-line usage: sh basic.sh /path/to/build
-
-if [ -z "$TESTJAVA" ]; then
-  if [ $# -lt 1 ]; then exit 1; fi
-  TESTJAVA="$1"; shift
-  COMPILEJAVA="${TESTJAVA}"
-  TESTSRC="`pwd`"
-  TESTCLASSES="`pwd`"
-fi
-
-JAVA="$TESTJAVA/bin/java"
-JAR="$COMPILEJAVA/bin/jar"
-
-OS=`uname -s`
-case "$OS" in
-    SunOS | Darwin | AIX )
-      FS='/'
-      SEP=':' ;;
-    Linux )
-      FS='/'
-      SEP=':' ;;
-    * )
-      FS='\\'
-      SEP='\;' ;;
-esac
-
-JARD=x.jar
-EXTD=x.ext
-TESTD=x.test
-P3JAR=${EXTD}${FS}p3.jar
-
-if [ \! -d $EXTD ]; then
-    # Initialize
-    echo Initializing...
-    rm -rf $JARD $EXTD $TESTD
-    mkdir -p $JARD $EXTD $TESTD
-
-    for n in 2 3; do
-      rm -rf $JARD/*; mkdir -p $JARD/META-INF/services
-      echo FooProvider$n \
-        >$JARD/META-INF/services/FooService
-      cp $TESTCLASSES/FooProvider$n.class $JARD
-      if [ $n = 3 ]; then
-        cp $TESTCLASSES/FooService.class $JARD
-      fi
-      (cd $JARD; "$JAR" ${TESTTOOLVMOPTS} -cf ../p$n.jar *)
-    done
-
-    mv p3.jar $EXTD
-
-    cp $TESTCLASSES/Load.class $TESTD
-    cp $TESTCLASSES/FooService.class $TESTD
-    cp $TESTCLASSES/FooProvider1.class $TESTD
-    mkdir -p $TESTD/META-INF/services
-    echo FooProvider1 \
-      >$TESTD/META-INF/services/FooService
-
-    # This gives us:
-    #   $TESTD: FooProvider1
-    #   .     : FooProvider2, in p2.jar
-    #   $EXTD:  FooProvider3, in p3.jar
-
-fi
-
-failures=0
-
-go() {
-  echo ''
-  cp="$1"; shift
-  if [ -z "$cp" ]; then cp="$TESTCLASSES"; else cp="$TESTCLASSES$SEP$cp"; fi
-  vmargs="$1"; shift
-  sh -xc "'$JAVA' ${TESTVMOPTS} -cp $cp $vmargs $T $*" 2>&1
-  if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
-}
-
-
-# Java-level tests
-
-T=Basic
-go ".${SEP}$TESTD${SEP}p2.jar" ""
-
-# Success cases
-
-T=Load
-
-go "$TESTD" "" FooProvider1
-
-go ".${SEP}p2.jar" "" FooProvider2
-
-go "${P3JAR}${SEP}p2.jar" "" FooProvider3 FooProvider2
-
-go "$TESTD${SEP}p2.jar" "" FooProvider1 FooProvider2
-
-go "${P3JAR}${SEP}$TESTD" "" FooProvider3 FooProvider1
-
-go "${P3JAR}${SEP}$TESTD${SEP}p2.jar" "" \
-  FooProvider3 FooProvider1 FooProvider2
-
-# Failure cases
-
-mkdir -p x.meta/META-INF/services
-
-# Simple failures
-for p in FooProvider42 'blah blah' 9234 'X!' java.lang.Object; do
-  echo $p >x.meta/META-INF/services/FooService
-  go ".${SEP}x.meta" "" fail
-done
-
-# Failures followed by successes
-echo FooProvider42 >x.meta/META-INF/services/FooService
-go "$TESTD${SEP}x.meta" "" FooProvider1 fail
-go "x.meta${SEP}$TESTD" "" fail FooProvider1
-go "$TESTD${SEP}x.meta${SEP}${SEP}p2.jar" "" \
-  FooProvider1 fail FooProvider2
-
-
-# Summary
-
-echo ''
-if [ $failures -gt 0 ];
-  then echo "$failures case(s) failed";
-  else echo "All cases passed"; fi
-exit $failures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/BarProvider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * 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 BarProvider { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/Basic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//
+
+import java.io.*;
+import java.util.*;
+
+
+public class Basic {
+
+    private static PrintStream out = System.err;
+
+    private static <T> Set<T> setOf(Iterable<T> it) {
+        Set<T> s = new HashSet<T>();
+        for (T t : it)
+            s.add(t);
+        return s;
+    }
+
+    private static <T> void checkEquals(Set<T> s1, Set<T> s2, boolean eq) {
+        if (s1.equals(s2) != eq)
+            throw new RuntimeException(String.format("%b %s : %s",
+                                                     eq, s1, s2));
+    }
+
+    abstract static class TestLoader {
+        String name;
+
+        TestLoader(String name) { this.name = name; }
+
+        abstract ServiceLoader<FooService> load();
+    }
+
+    static TestLoader tcclLoader = new TestLoader("Thread context class loader") {
+        ServiceLoader<FooService> load() {
+            return ServiceLoader.load(FooService.class);
+        }
+    };
+
+    static TestLoader systemClLoader = new TestLoader("System class loader") {
+        ServiceLoader<FooService> load() {
+            return ServiceLoader.load(FooService.class, ClassLoader.getSystemClassLoader());
+        }
+    };
+
+    static TestLoader nullClLoader = new TestLoader("null (defer to system class loader)") {
+        ServiceLoader<FooService> load() {
+            return ServiceLoader.load(FooService.class, null);
+        }
+    };
+
+    public static void main(String[] args) {
+        for (TestLoader tl : Arrays.asList(tcclLoader, systemClLoader, nullClLoader)) {
+            test(tl);
+        }
+    }
+
+    static void test(TestLoader tl) {
+        ServiceLoader<FooService> sl = tl.load();
+        out.format("%s: %s%n", tl.name, sl);
+
+        // Providers are cached
+        Set<FooService> ps = setOf(sl);
+        checkEquals(ps, setOf(sl), true);
+
+        // The cache can be flushed and reloaded
+        sl.reload();
+        checkEquals(ps, setOf(sl), false);
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider1.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 FooProvider1 extends FooService { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider2.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 FooProvider2 extends FooService { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider3.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 FooProvider3 extends FooService { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/FooService.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 abstract class FooService { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/Load.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.*;
+import java.util.*;
+
+
+public class Load {
+
+    private static PrintStream out = System.err;
+
+    public static void main(String[] args) throws Exception {
+
+        boolean installedOnly = false;
+
+        List<String> expected = new ArrayList<String>(Arrays.asList(args));
+        if (!expected.isEmpty() && expected.get(0).equals("-i")) {
+            expected.remove(0);
+            installedOnly = true;
+        }
+        if (expected.isEmpty())
+            throw new Exception("usage: Load [-i] ( fail | provider-class-name )*");
+
+        ServiceLoader<FooService> sl = (installedOnly
+                                        ? ServiceLoader.loadInstalled(FooService.class)
+                                        : ServiceLoader.load(FooService.class));
+        out.format("%s%n", sl);
+        Iterator<FooService> sli = sl.iterator();
+        Iterator<String> ei = expected.iterator();
+
+        for (;; ei.remove()) {
+            FooService fp = null;
+            try {
+                if (!sli.hasNext())
+                    break;
+                fp = sli.next();
+            } catch (ServiceConfigurationError x) {
+                if (ei.next().equals("fail")) {
+                    out.format("Failed as expected: %s%n", x);
+                    continue;
+                }
+                throw x;
+            }
+            String ec = ei.next();
+            if (!fp.getClass().getName().equals(ec))
+                throw new
+                    Exception(String.format("Wrong provider %s; expected %s",
+                                            fp.getClass().getName(), ec));
+            out.format("Provider found: %s%n", fp.getClass().getName());
+        }
+
+        if (ei.hasNext())
+            throw new Exception("Missing providers: " + expected);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/basic.sh	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,153 @@
+#
+# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# 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 4640520 6354623 7198496
+# @summary Unit test for java.util.ServiceLoader
+#
+# @build Basic Load FooService FooProvider1 FooProvider2 FooProvider3 BarProvider
+# @run shell basic.sh
+
+# Command-line usage: sh basic.sh /path/to/build
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVA="$TESTJAVA/bin/java"
+JAR="$COMPILEJAVA/bin/jar"
+
+OS=`uname -s`
+case "$OS" in
+    SunOS | Darwin | AIX )
+      FS='/'
+      SEP=':' ;;
+    Linux )
+      FS='/'
+      SEP=':' ;;
+    * )
+      FS='\\'
+      SEP='\;' ;;
+esac
+
+JARD=x.jar
+EXTD=x.ext
+TESTD=x.test
+P3JAR=${EXTD}${FS}p3.jar
+
+if [ \! -d $EXTD ]; then
+    # Initialize
+    echo Initializing...
+    rm -rf $JARD $EXTD $TESTD
+    mkdir -p $JARD $EXTD $TESTD
+
+    for n in 2 3; do
+      rm -rf $JARD/*; mkdir -p $JARD/META-INF/services
+      echo FooProvider$n \
+        >$JARD/META-INF/services/FooService
+      cp $TESTCLASSES/FooProvider$n.class $JARD
+      if [ $n = 3 ]; then
+        cp $TESTCLASSES/FooService.class $JARD
+      fi
+      (cd $JARD; "$JAR" ${TESTTOOLVMOPTS} -cf ../p$n.jar *)
+    done
+
+    mv p3.jar $EXTD
+
+    cp $TESTCLASSES/Load.class $TESTD
+    cp $TESTCLASSES/FooService.class $TESTD
+    cp $TESTCLASSES/FooProvider1.class $TESTD
+    mkdir -p $TESTD/META-INF/services
+    echo FooProvider1 \
+      >$TESTD/META-INF/services/FooService
+
+    # This gives us:
+    #   $TESTD: FooProvider1
+    #   .     : FooProvider2, in p2.jar
+    #   $EXTD:  FooProvider3, in p3.jar
+
+fi
+
+failures=0
+
+go() {
+  echo ''
+  cp="$1"; shift
+  if [ -z "$cp" ]; then cp="$TESTCLASSES"; else cp="$TESTCLASSES$SEP$cp"; fi
+  vmargs="$1"; shift
+  sh -xc "'$JAVA' ${TESTVMOPTS} -cp $cp $vmargs $T $*" 2>&1
+  if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
+}
+
+
+# Java-level tests
+
+T=Basic
+go ".${SEP}$TESTD${SEP}p2.jar" ""
+
+# Success cases
+
+T=Load
+
+go "$TESTD" "" FooProvider1
+
+go ".${SEP}p2.jar" "" FooProvider2
+
+go "${P3JAR}${SEP}p2.jar" "" FooProvider3 FooProvider2
+
+go "$TESTD${SEP}p2.jar" "" FooProvider1 FooProvider2
+
+go "${P3JAR}${SEP}$TESTD" "" FooProvider3 FooProvider1
+
+go "${P3JAR}${SEP}$TESTD${SEP}p2.jar" "" \
+  FooProvider3 FooProvider1 FooProvider2
+
+# Failure cases
+
+mkdir -p x.meta/META-INF/services
+
+# Simple failures
+for p in FooProvider42 'blah blah' 9234 'X!' BarProvider; do
+  echo $p >x.meta/META-INF/services/FooService
+  go ".${SEP}x.meta" "" fail
+done
+
+# Failures followed by successes
+echo FooProvider42 >x.meta/META-INF/services/FooService
+go "$TESTD${SEP}x.meta" "" FooProvider1 fail
+go "x.meta${SEP}$TESTD" "" fail FooProvider1
+go "$TESTD${SEP}x.meta${SEP}${SEP}p2.jar" "" \
+  FooProvider1 fail FooProvider2
+
+
+# Summary
+
+echo ''
+if [ $failures -gt 0 ];
+  then echo "$failures case(s) failed";
+  else echo "All cases passed"; fi
+exit $failures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,196 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build CompilerUtils
+ * @run testng/othervm BadProvidersTest
+ * @summary Basic test of ServiceLoader with bad provider and bad provider
+ *          factories deployed on the module path
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.ServiceLoader.Provider;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.*;
+
+/**
+ * Basic test of `provides S with PF` and `provides S with P` where the provider
+ * factory or provider
+ */
+
+public class BadProvidersTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path USER_DIR   = Paths.get(System.getProperty("user.dir"));
+    private static final Path SRC_DIR    = Paths.get(TEST_SRC, "modules");
+
+    private static final Path BADFACTORIES_DIR = Paths.get(TEST_SRC, "badfactories");
+    private static final Path BADPROVIDERS_DIR = Paths.get(TEST_SRC, "badproviders");
+
+    private static final String TEST1_MODULE = "test1";
+    private static final String TEST2_MODULE = "test2";
+
+    private static final String TEST_SERVICE = "p.Service";
+
+    /**
+     * Compiles a module, returning a module path with the compiled module.
+     */
+    private Path compileTest(String moduleName) throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Path output = Files.createDirectory(dir.resolve(moduleName));
+        boolean compiled = CompilerUtils.compile(SRC_DIR.resolve(moduleName), output);
+        assertTrue(compiled);
+        return dir;
+    }
+
+    /**
+     * Resolves a test module and loads it into its own layer. ServiceLoader
+     * is then used to load all providers.
+     */
+    private List<Provider> loadProviders(Path mp, String moduleName) throws Exception {
+        ModuleFinder finder = ModuleFinder.of(mp);
+
+        Layer bootLayer = Layer.boot();
+
+        Configuration cf = bootLayer.configuration()
+                .resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of(moduleName));
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl);
+
+        Class<?> service = layer.findLoader(moduleName).loadClass(TEST_SERVICE);
+
+        return ServiceLoader.load(layer, service)
+                .stream()
+                .collect(Collectors.toList());
+    }
+
+    @Test
+    public void sanityTest1() throws Exception {
+        Path mods = compileTest(TEST1_MODULE);
+        List<Provider> list = loadProviders(mods, TEST1_MODULE);
+        assertTrue(list.size() == 1);
+
+        // the provider is a singleton, enforced by the provider factory
+        Object p1 = list.get(0).get();
+        Object p2 = list.get(0).get();
+        assertTrue(p1 != null);
+        assertTrue(p1 == p2);
+    }
+
+    @Test
+    public void sanityTest2() throws Exception {
+        Path mods = compileTest(TEST2_MODULE);
+        List<Provider> list = loadProviders(mods, TEST2_MODULE);
+        assertTrue(list.size() == 1);
+        Object p = list.get(0).get();
+        assertTrue(p != null);
+    }
+
+
+    @DataProvider(name = "badfactories")
+    public Object[][] createBadFactories() {
+        return new Object[][] {
+                { "classnotpublic",     null },
+                { "methodnotpublic",    null },
+                { "badreturntype",      null },
+                { "returnsnull",        null },
+                { "throwsexception",    null },
+        };
+    }
+
+
+    @Test(dataProvider = "badfactories",
+          expectedExceptions = ServiceConfigurationError.class)
+    public void testBadFactory(String testName, String ignore) throws Exception {
+        Path mods = compileTest(TEST1_MODULE);
+
+        // compile the bad factory
+        Path source = BADFACTORIES_DIR.resolve(testName);
+        Path output = Files.createTempDirectory(USER_DIR, "tmp");
+        boolean compiled = CompilerUtils.compile(source, output);
+        assertTrue(compiled);
+
+        // copy the compiled class into the module
+        Path classFile = Paths.get("p", "ProviderFactory.class");
+        Files.copy(output.resolve(classFile),
+                   mods.resolve(TEST1_MODULE).resolve(classFile),
+                   StandardCopyOption.REPLACE_EXISTING);
+
+        // load providers and instantiate each one
+        loadProviders(mods, TEST1_MODULE).forEach(Provider::get);
+    }
+
+
+    @DataProvider(name = "badproviders")
+    public Object[][] createBadProviders() {
+        return new Object[][] {
+                { "notpublic",          null },
+                { "ctornotpublic",      null },
+                { "notasubtype",        null },
+                { "throwsexception",    null }
+        };
+    }
+
+
+    @Test(dataProvider = "badproviders",
+          expectedExceptions = ServiceConfigurationError.class)
+    public void testBadProvider(String testName, String ignore) throws Exception {
+        Path mods = compileTest(TEST2_MODULE);
+
+        // compile the bad provider
+        Path source = BADPROVIDERS_DIR.resolve(testName);
+        Path output = Files.createTempDirectory(USER_DIR, "tmp");
+        boolean compiled = CompilerUtils.compile(source, output);
+        assertTrue(compiled);
+
+        // copy the compiled class into the module
+        Path classFile = Paths.get("p", "Provider.class");
+        Files.copy(output.resolve(classFile),
+                   mods.resolve(TEST2_MODULE).resolve(classFile),
+                   StandardCopyOption.REPLACE_EXISTING);
+
+        // load providers and instantiate each one
+        loadProviders(mods, TEST2_MODULE).forEach(Provider::get);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/Basic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,432 @@
+/*
+ * 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
+ * @library modules
+ * @build bananascript/*
+ * @compile src/pearscript/org/pear/PearScriptEngineFactory.java
+ *          src/pearscript/org/pear/PearScript.java
+ * @run testng/othervm Basic
+ * @summary Basic test for ServiceLoader with a provider deployed as a module.
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.*;
+import java.util.ServiceLoader.Provider;
+import java.util.stream.Collectors;
+import javax.script.ScriptEngineFactory;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeTest;
+import static org.testng.Assert.*;
+
+/**
+ * Basic test for ServiceLoader. The test make use of two service providers:
+ * 1. BananaScriptEngine - a ScriptEngineFactory deployed as a module on the
+ *    module path. It implementations a singleton via the public static
+ *    provider method.
+ * 2. PearScriptEngine - a ScriptEngineFactory deployed on the class path
+ *    with a service configuration file.
+ */
+
+public class Basic {
+
+    // Copy the services configuration file for "pearscript" into place.
+    @BeforeTest
+    public void setup() throws Exception {
+        Path src = Paths.get(System.getProperty("test.src", ""));
+        Path classes = Paths.get(System.getProperty("test.classes", ""));
+        String st = ScriptEngineFactory.class.getName();
+        Path config = Paths.get("META-INF", "services", st);
+        Path source = src.resolve("src").resolve("pearscript").resolve(config);
+        Path target = classes.resolve(config);
+        Files.createDirectories(target.getParent());
+        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
+    }
+
+    /**
+     * Basic test of iterator() to ensure that providers located as modules
+     * and on the class path are found.
+     */
+    @Test
+    public void testIterator() {
+        ServiceLoader<ScriptEngineFactory> loader
+            = ServiceLoader.load(ScriptEngineFactory.class);
+        Set<String> names = collectAll(loader)
+                .stream()
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertTrue(names.contains("BananaScriptEngine"));
+        assertTrue(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of iterator() to test iteration order. Providers deployed
+     * as named modules should be found before providers deployed on the class
+     * path.
+     */
+    @Test
+    public void testIteratorOrder() {
+        ServiceLoader<ScriptEngineFactory> loader
+            = ServiceLoader.load(ScriptEngineFactory.class);
+        boolean foundUnnamed = false;
+        for (ScriptEngineFactory factory : collectAll(loader)) {
+            if (factory.getClass().getModule().isNamed()) {
+                if (foundUnnamed) {
+                    assertTrue(false, "Named module element after unnamed");
+                }
+            } else {
+                foundUnnamed = true;
+            }
+        }
+    }
+
+    /**
+     * Basic test of Provider::type
+     */
+    @Test
+    public void testProviderType() {
+        Set<String> types = ServiceLoader.load(ScriptEngineFactory.class)
+                .stream()
+                .map(Provider::type)
+                .map(Class::getName)
+                .collect(Collectors.toSet());
+        assertTrue(types.contains("org.banana.BananaScriptEngineFactory"));
+        assertTrue(types.contains("org.pear.PearScriptEngineFactory"));
+    }
+
+    /**
+     * Basic test of Provider::get
+     */
+    @Test
+    public void testProviderGet() {
+        Set<String> names = ServiceLoader.load(ScriptEngineFactory.class)
+                .stream()
+                .map(Provider::get)
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertTrue(names.contains("BananaScriptEngine"));
+        assertTrue(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of the public static provider method. BananaScriptEngine
+     * defines a provider method that returns the same instance.
+     */
+    @Test
+    public void testSingleton() {
+        Optional<Provider<ScriptEngineFactory>> oprovider
+            = ServiceLoader.load(ScriptEngineFactory.class)
+                .stream()
+                .filter(p -> p.type().getName().equals("org.banana.BananaScriptEngineFactory"))
+                .findFirst();
+        assertTrue(oprovider.isPresent());
+        Provider<ScriptEngineFactory> provider = oprovider.get();
+
+        // invoke Provider::get twice
+        ScriptEngineFactory factory1 = provider.get();
+        ScriptEngineFactory factory2 = provider.get();
+        assertTrue(factory1 == factory2);
+    }
+
+    /**
+     * Basic test of stream() to ensure that elements for providers in named
+     * modules come before elements for providers in unnamed modules.
+     */
+    @Test
+    public void testStreamOrder() {
+        List<Class<?>> types = ServiceLoader.load(ScriptEngineFactory.class)
+                .stream()
+                .map(Provider::type)
+                .collect(Collectors.toList());
+
+        boolean foundUnnamed = false;
+        for (Class<?> factoryClass : types) {
+            if (factoryClass.getModule().isNamed()) {
+                if (foundUnnamed) {
+                    assertTrue(false, "Named module element after unnamed");
+                }
+            } else {
+                foundUnnamed = true;
+            }
+        }
+    }
+
+    /**
+     * Basic test of ServiceLoader.findFirst()
+     */
+    @Test
+    public void testFindFirst() {
+        Optional<ScriptEngineFactory> ofactory
+            = ServiceLoader.load(ScriptEngineFactory.class).findFirst();
+        assertTrue(ofactory.isPresent());
+        ScriptEngineFactory factory = ofactory.get();
+        assertTrue(factory.getClass().getModule().isNamed());
+
+        class S { }
+        assertFalse(ServiceLoader.load(S.class).findFirst().isPresent());
+    }
+
+    /**
+     * Basic test ServiceLoader.load specifying the platform class loader.
+     * The providers on the module path and class path should not be located.
+     */
+    @Test
+    public void testWithPlatformClassLoader() {
+        ClassLoader pcl = ClassLoader.getPlatformClassLoader();
+
+        // iterator
+        ServiceLoader<ScriptEngineFactory> loader
+                = ServiceLoader.load(ScriptEngineFactory.class, pcl);
+        Set<String> names = collectAll(loader)
+                .stream()
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertFalse(names.contains("BananaScriptEngine"));
+        assertFalse(names.contains("PearScriptEngine"));
+
+        // stream
+        names = ServiceLoader.load(ScriptEngineFactory.class, pcl)
+                .stream()
+                .map(Provider::get)
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertFalse(names.contains("BananaScriptEngine"));
+        assertFalse(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of ServiceLoader.load, using the class loader for
+     * a module in a custom layer as the context.
+     */
+    @Test
+    public void testWithCustomLayer1() {
+        Layer layer = createCustomLayer("bananascript");
+
+        ClassLoader loader = layer.findLoader("bananascript");
+        List<ScriptEngineFactory> providers
+            = collectAll(ServiceLoader.load(ScriptEngineFactory.class, loader));
+
+        // should have at least 2 x bananascript + pearscript
+        assertTrue(providers.size() >= 3);
+
+        // first element should be the provider in the custom layer
+        ScriptEngineFactory factory = providers.get(0);
+        assertTrue(factory.getClass().getClassLoader() == loader);
+        assertTrue(factory.getClass().getModule().getLayer() == layer);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+
+        // remainder should be the boot layer
+        providers.remove(0);
+        Set<String> names = providers.stream()
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertTrue(names.contains("BananaScriptEngine"));
+        assertTrue(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of ServiceLoader.load using a custom Layer as the context.
+     */
+    @Test
+    public void testWithCustomLayer2() {
+        Layer layer = createCustomLayer("bananascript");
+
+        List<ScriptEngineFactory> factories
+            = collectAll(ServiceLoader.load(layer, ScriptEngineFactory.class));
+
+        // should have at least 2 x bananascript
+        assertTrue(factories.size() >= 2);
+
+        // first element should be the provider in the custom layer
+        ScriptEngineFactory factory = factories.get(0);
+        assertTrue(factory.getClass().getModule().getLayer() == layer);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+
+        // remainder should be the boot layer
+        factories.remove(0);
+        Set<String> names = factories.stream()
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertTrue(names.contains("BananaScriptEngine"));
+        assertFalse(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of ServiceLoader.load with a tree of layers.
+     *
+     * Test scenario:
+     * - boot layer contains "bananascript", maybe other script engines
+     * - layer1, with boot layer as parent, contains "bananascript"
+     * - layer2, with boot layer as parent, contains "bananascript"
+     * - layer3, with layer1 ad layer as parents, contains "bananascript"
+     *
+     * ServiceLoader should locate all 4 script engine factories in DFS order.
+     */
+    @Test
+    public void testWithCustomLayer3() {
+        Layer bootLayer = Layer.boot();
+        Configuration cf0 = bootLayer.configuration();
+
+        // boot layer should contain "bananascript"
+        List<ScriptEngineFactory> factories
+            = collectAll(ServiceLoader.load(bootLayer, ScriptEngineFactory.class));
+        int countInBootLayer = factories.size();
+        assertTrue(countInBootLayer >= 1);
+        assertTrue(factories.stream()
+                .map(p -> p.getEngineName())
+                .filter("BananaScriptEngine"::equals)
+                .findAny()
+                .isPresent());
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Path dir = Paths.get(System.getProperty("test.classes", "."), "modules");
+        ModuleFinder finder = ModuleFinder.of(dir);
+
+        // layer1
+        Configuration cf1 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of());
+        Layer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl);
+        assertTrue(layer1.modules().size() == 1);
+
+        // layer2
+        Configuration cf2 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of());
+        Layer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl);
+        assertTrue(layer2.modules().size() == 1);
+
+        // layer3 with layer1 and layer2 as parents
+        Configuration cf3 = Configuration.resolveRequiresAndUses(finder,
+                List.of(cf1, cf2),
+                ModuleFinder.of(),
+                Set.of());
+        Layer layer3 = Layer.defineModulesWithOneLoader(cf3, List.of(layer1, layer2), scl).layer();
+        assertTrue(layer3.modules().size() == 1);
+
+
+        // class loaders
+        ClassLoader loader1 = layer1.findLoader("bananascript");
+        ClassLoader loader2 = layer2.findLoader("bananascript");
+        ClassLoader loader3 = layer3.findLoader("bananascript");
+        assertTrue(loader1 != loader2);
+        assertTrue(loader1 != loader3);
+        assertTrue(loader2 != loader3);
+
+        // load all factories with layer3 as the context
+        factories = collectAll(ServiceLoader.load(layer3, ScriptEngineFactory.class));
+        int count = factories.size();
+        assertTrue(count == countInBootLayer + 3);
+
+        // the ordering should be layer3, layer1, boot layer, layer2
+
+        ScriptEngineFactory factory = factories.get(0);
+        assertTrue(factory.getClass().getModule().getLayer() == layer3);
+        assertTrue(factory.getClass().getClassLoader() == loader3);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+
+        factory = factories.get(1);
+        assertTrue(factory.getClass().getModule().getLayer() == layer1);
+        assertTrue(factory.getClass().getClassLoader() == loader1);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+
+        // boot layer "bananascript" and maybe other factories
+        int last = count -1;
+        boolean found = false;
+        for (int i=2; i<last; i++) {
+            factory = factories.get(i);
+            assertTrue(factory.getClass().getModule().getLayer() == bootLayer);
+            if (factory.getEngineName().equals("BananaScriptEngine")) {
+                assertFalse(found);
+                found = true;
+            }
+        }
+        assertTrue(found);
+
+        factory = factories.get(last);
+        assertTrue(factory.getClass().getModule().getLayer() == layer2);
+        assertTrue(factory.getClass().getClassLoader() == loader2);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+    }
+
+
+    // -- nulls --
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull1() {
+        ServiceLoader.load(null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull2() {
+        ServiceLoader.load((Class<?>) null, ClassLoader.getSystemClassLoader());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull3() {
+        class S { }
+        ServiceLoader.load((Layer) null, S.class);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull4() {
+        ServiceLoader.load(Layer.empty(), null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull5() {
+        ServiceLoader.loadInstalled(null);
+    }
+
+    /**
+     * Create a custom Layer by resolving the given module names. The modules
+     * are located in the {@code ${test.classes}/modules} directory.
+     */
+    private Layer createCustomLayer(String... modules) {
+        Path dir = Paths.get(System.getProperty("test.classes", "."), "modules");
+        ModuleFinder finder = ModuleFinder.of(dir);
+        Set<String> roots = new HashSet<>();
+        Collections.addAll(roots, modules);
+        Layer bootLayer = Layer.boot();
+        Configuration parent = bootLayer.configuration();
+        Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), roots);
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
+        assertTrue(layer.modules().size() == 1);
+        return layer;
+    }
+
+    private <E> List<E> collectAll(ServiceLoader<E> loader) {
+        List<E> list = new ArrayList<>();
+        Iterator<E> iterator = loader.iterator();
+        while (iterator.hasNext()) {
+            list.add(iterator.next());
+        }
+        return list;
+    }
+}
+
--- a/jdk/test/java/util/ServiceLoader/modules/MiscTests.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.lang.reflect.Layer;
-import java.security.Provider;
-import java.util.ServiceLoader;
-
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-/*
- * @test
- * @run testng MiscTests
- * @summary Basic test of ServiceLoader with modules
- */
-
-public class MiscTests {
-
-    @Test
-    public void testEmptyLayer() {
-        ServiceLoader<Provider> sl
-            = ServiceLoader.load(Layer.empty(), Provider.class);
-        assertFalse(sl.iterator().hasNext());
-    }
-
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testNullLayer() {
-        ServiceLoader.load(null, Provider.class);
-    }
-
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testNullService() {
-        ServiceLoader.load(Layer.empty(), null);
-    }
-
-}
--- a/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-/*
- * Copyright (c) 2015, 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.File;
-import java.lang.module.Configuration;
-import java.lang.module.ModuleFinder;
-import java.lang.reflect.Layer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ServiceLoader;
-import java.util.Set;
-import javax.script.ScriptEngineFactory;
-
-import static jdk.testlibrary.ProcessTools.executeTestJava;
-
-import org.testng.annotations.BeforeTest;
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-/**
- * @test
- * @library /lib/testlibrary
- * @modules java.scripting
- *          jdk.compiler
- * @build ServicesTest CompilerUtils jdk.testlibrary.*
- * @run testng ServicesTest
- * @summary Tests ServiceLoader to locate service providers on the module path
- *          and class path. Also tests ServiceLoader with a custom Layer.
- */
-
-@Test
-public class ServicesTest {
-
-    private static final String TEST_SRC = System.getProperty("test.src");
-
-    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
-    private static final Path CLASSES_DIR = Paths.get("classes");
-    private static final Path MODS_DIR = Paths.get("mods");
-
-    // modules to compile to the module path
-    private static final String MODULES[] = { "test", "bananascript" };
-
-    // directories of classes to compile to the class path
-    private static final String CLASSES[] = { "pearscript" };
-
-    // resources to copy to the class path
-    private static final String RESOURCES[] = {
-        "pearscript/META-INF/services/javax.script.ScriptEngineFactory"
-    };
-
-
-    /**
-     * Compiles all modules and classes used by the test
-     */
-    @BeforeTest
-    public void setup() throws Exception {
-
-        // modules
-        for (String mn : MODULES ) {
-            Path src = SRC_DIR.resolve(mn);
-            Path mods = MODS_DIR.resolve(mn);
-            assertTrue(CompilerUtils.compile(src, mods));
-        }
-
-        // classes
-        for (String dir : CLASSES) {
-            Path src = SRC_DIR.resolve(dir);
-            assertTrue(CompilerUtils.compile(src, CLASSES_DIR));
-        }
-
-        // copy resources
-        for (String rn : RESOURCES) {
-            Path file = Paths.get(rn.replace('/', File.separatorChar));
-            Path source = SRC_DIR.resolve(file);
-
-            // drop directory to get a target of classes/META-INF/...
-            Path target = CLASSES_DIR.resolve(file.subpath(1, file.getNameCount()));
-
-            Files.createDirectories(target.getParent());
-            Files.copy(source, target);
-        }
-
-    }
-
-
-    /**
-     * Run test with --module-path.
-     *
-     * BananaScriptEngine should be found.
-     */
-    public void runWithModulePath() throws Exception {
-        int exitValue
-            = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "--add-modules", "bananascript",
-                              "-m", "test/test.Main",
-                              "BananaScriptEngine")
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
-
-        assertTrue(exitValue == 0);
-    }
-
-
-    /**
-     * Run test with --module-path and -classpath.
-     *
-     * Both BananaScriptEngine and PearScriptEngine should be found
-     */
-    public void runWithModulePathAndClassPath() throws Exception {
-        int exitValue
-            = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "-cp", CLASSES_DIR.toString(),
-                              "--add-modules", "bananascript",
-                              "-m", "test/test.Main",
-                              "BananaScriptEngine", "PearScriptEngine")
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
-
-        assertTrue(exitValue == 0);
-    }
-
-
-    /**
-     * Exercise ServiceLoader.load(Layer, Class).
-     */
-    public void testWithCustomLayer() throws Exception {
-
-        ServiceLoader<ScriptEngineFactory> sl;
-
-        // BananaScriptEngine should not be in the boot Layer
-        sl = ServiceLoader.load(Layer.boot(), ScriptEngineFactory.class);
-        assertTrue(find("BananaScriptEngine", sl) == null);
-
-        // create a custom Layer
-        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
-        Layer bootLayer = Layer.boot();
-        Configuration parent = bootLayer.configuration();
-        Configuration cf
-            = parent.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of());
-        ClassLoader scl = ClassLoader.getSystemClassLoader();
-        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
-
-        assertTrue(layer.findModule("bananascript").isPresent());
-        ClassLoader loader = layer.findLoader("bananascript");
-
-        sl = ServiceLoader.load(layer, ScriptEngineFactory.class);
-        ScriptEngineFactory factory = find("BananaScriptEngine", sl);
-        assertTrue(factory != null);
-        assertEquals(factory.getClass().getModule().getName(), "bananascript");
-        assertTrue(factory.getClass().getClassLoader() == loader);
-
-    }
-
-    /**
-     * Find the given scripting engine (by name) via the ScriptEngineFactory
-     * that ServiceLoader has found.
-     */
-    static ScriptEngineFactory find(String name,
-                                    ServiceLoader<ScriptEngineFactory> sl) {
-        for (ScriptEngineFactory factory : sl) {
-            if (factory.getEngineName().equals(name))
-                return factory;
-        }
-        return null;
-    }
-
-
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/badreturntype/ProviderFactory.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * 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 p;
+
+/**
+ * A provider factory with a provider() method with a return type that is not
+ * p.Service
+ */
+
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    public static Object provider() {
+        throw new RuntimeException("Should not be called");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/ProviderFactory.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package p;
+
+/**
+ * Not a provider factory because the class is not public.
+ */
+
+class ProviderFactory {
+    ProviderFactory() { }
+
+    public static Service provider() {
+        throw new RuntimeException("Should not be called");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/ProviderFactory.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package p;
+
+/**
+ * Not a provider factory because the static provider() method is not public.
+ */
+
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    static Service provider() {
+        throw new RuntimeException("Should not be called");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/ProviderFactory.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * 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 p;
+
+/**
+ * A provider factory that defines a public static provider method that returns
+ * null.
+ */
+
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    public static Service provider() {
+        return null;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/ProviderFactory.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package p;
+
+/**
+ * A provider factory that throws an exception.
+ */
+
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    public static Service provider() {
+        throw new RuntimeException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Provider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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 p;
+
+/**
+ * A provider class with a non-public constructor
+ */
+
+public class Provider implements Service {
+    Provider() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notasubtype/Provider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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 p;
+
+/**
+ * A provider class that is not a subtype of Service.
+ */
+
+public class Provider {
+    Provider() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Provider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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 p;
+
+/**
+ * Provider class not public.
+ */
+
+class Provider implements Service {
+    public Provider() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Provider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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 p;
+
+/**
+ * A provider class with a constructor throws an exception.
+ */
+
+public class Provider {
+    public Provider() {
+        throw new RuntimeException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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 p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+module bananascript {
+    requires java.scripting;
+
+    provides javax.script.ScriptEngineFactory
+        with org.banana.BananaScriptEngineFactory;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScript.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.banana;
+
+import java.io.Reader;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class BananaScript implements ScriptEngine {
+
+    @Override
+    public Object eval(String script, ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script, Bindings n) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , Bindings n) {
+        throw new RuntimeException();
+    }
+    @Override
+    public void put(String key, Object value) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object get(String key) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings getBindings(int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setBindings(Bindings bindings, int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings createBindings() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptContext getContext() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setContext(ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngineFactory getFactory() {
+        throw new RuntimeException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScriptEngineFactory.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.banana;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class BananaScriptEngineFactory implements ScriptEngineFactory {
+
+    static final BananaScriptEngineFactory INSTANCE  = new BananaScriptEngineFactory(null);
+
+    public BananaScriptEngineFactory() {
+        throw new RuntimeException("Should not be called");
+    }
+
+    private BananaScriptEngineFactory(Void param) { }
+
+    public static BananaScriptEngineFactory provider() {
+        return INSTANCE;
+    }
+
+    @Override
+    public String getEngineName() {
+        return "BananaScriptEngine";
+    }
+
+    @Override
+    public String getEngineVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public List<String> getExtensions() {
+        return Arrays.asList("banana");
+    }
+
+    @Override
+    public List<String> getMimeTypes() {
+        return Arrays.asList("application/x-bananascript");
+    }
+
+    @Override
+    public List<String> getNames() {
+        return Arrays.asList("BananaScript");
+    }
+
+    @Override
+    public String getLanguageName() {
+        return "BananaScript";
+    }
+
+    @Override
+    public String getLanguageVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public Object getParameter(String key) {
+        return null;
+    }
+
+    @Override
+    public String getMethodCallSyntax(String obj, String m, String... args) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getOutputStatement(String toDisplay) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getProgram(String... statements) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngine getScriptEngine() {
+        return new BananaScript();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+/**
+ * Test module that provides an implementation of p.Service via a
+ * provider factory class.
+ */
+
+module test1 {
+    exports p;
+    provides p.Service with p.ProviderFactory;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/ProviderFactory.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * 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 p;
+
+/**
+ * Provider factory
+ */
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    private static final Service INSTANCE = new Service() { };
+
+    public static Service provider() {
+        return INSTANCE;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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 p;
+
+/**
+ * Service type
+ */
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+/**
+ * Test module that provides an implementation of p.Service.
+ */
+
+module test2 {
+    exports p;
+    provides p.Service with p.Provider;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Provider.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+package p;
+
+/**
+ * Provider type
+ */
+public class Provider implements Service {
+    public Provider() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Service.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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 p;
+
+/**
+ * Service type
+ */
+public interface Service { }
--- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module bananascript {
-    requires java.scripting;
-
-    provides javax.script.ScriptEngineFactory
-      with org.banana.BananaScriptEngineFactory;
-}
-
--- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.banana;
-
-import java.io.Reader;
-import javax.script.Bindings;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-
-public class BananaScript implements ScriptEngine {
-
-    @Override
-    public Object eval(String script, ScriptContext context) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(Reader reader , ScriptContext context) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(String script) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(Reader reader) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(String script, Bindings n) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(Reader reader , Bindings n) {
-        throw new RuntimeException();
-    }
-    @Override
-    public void put(String key, Object value) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object get(String key) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Bindings getBindings(int scope) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public void setBindings(Bindings bindings, int scope) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Bindings createBindings() {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public ScriptContext getContext() {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public void setContext(ScriptContext context) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public ScriptEngineFactory getFactory() {
-        throw new RuntimeException();
-    }
-}
-
--- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.banana;
-
-import java.util.Arrays;
-import java.util.List;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-
-public class BananaScriptEngineFactory implements ScriptEngineFactory {
-
-    @Override
-    public String getEngineName() {
-        return "BananaScriptEngine";
-    }
-
-    @Override
-    public String getEngineVersion() {
-        return "1.0";
-    }
-
-    @Override
-    public List<String> getExtensions() {
-        return Arrays.asList("banana");
-    }
-
-    @Override
-    public List<String> getMimeTypes() {
-        return Arrays.asList("application/x-bananascript");
-    }
-
-    @Override
-    public List<String> getNames() {
-        return Arrays.asList("BananaScript");
-    }
-
-    @Override
-    public String getLanguageName() {
-        return "BananaScript";
-    }
-
-    @Override
-    public String getLanguageVersion() {
-        return "1.0";
-    }
-
-    @Override
-    public Object getParameter(String key) {
-        return null;
-    }
-
-    @Override
-    public String getMethodCallSyntax(String obj, String m, String... args) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public String getOutputStatement(String toDisplay) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public String getProgram(String... statements) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public ScriptEngine getScriptEngine() {
-        return new BananaScript();
-    }
-}
--- a/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,6 +30,12 @@
 
 public class PearScriptEngineFactory implements ScriptEngineFactory {
 
+    public PearScriptEngineFactory() { }
+
+    public static PearScriptEngineFactory provider() {
+        throw new RuntimeException("Should not be called");
+    }
+
     @Override
     public String getEngineName() {
         return "PearScriptEngine";
--- a/jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module test {
-    requires java.scripting;
-
-    uses javax.script.ScriptEngineFactory;
-}
-
--- a/jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package test;
-
-import java.util.HashSet;
-import java.util.ServiceLoader;
-import java.util.Set;
-import javax.script.ScriptEngineFactory;
-
-public class Main {
-    public static void main(String[] args) {
-        Set<String> engines = new HashSet<>();
-        for (ScriptEngineFactory factory: ServiceLoader.load(ScriptEngineFactory.class)) {
-            System.out.format("loaded: %s%n" , factory.getEngineName());
-            engines.add(factory.getEngineName());
-        }
-
-        for (String engine: args) {
-            if (!engines.contains(engine))
-                throw new RuntimeException(engine + " not found");
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Spliterator/SpliteratorFailFastTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.Spliterator;
+import java.util.Stack;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+import java.util.WeakHashMap;
+import java.util.function.Supplier;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * @test
+ * @bug 8148748
+ * @summary Spliterator fail-fast tests
+ * @run testng SpliteratorFailFastTest
+ */
+
+@Test
+public class SpliteratorFailFastTest extends SpliteratorLateBindingFailFastHelper {
+
+    static Object[][] spliteratorDataProvider;
+
+    @DataProvider(name = "Source")
+    public static Object[][] spliteratorDataProvider() {
+        if (spliteratorDataProvider != null) {
+            return spliteratorDataProvider;
+        }
+
+        List<Object[]> data = new ArrayList<>();
+        SpliteratorDataBuilder<Integer> db =
+                new SpliteratorDataBuilder<>(data, 5, Arrays.asList(1, 2, 3, 4));
+
+        // Collections
+
+        db.addList(ArrayList::new);
+
+        db.addList(LinkedList::new);
+
+        db.addList(Vector::new);
+
+        db.addList(AbstractRandomAccessListImpl::new);
+
+        db.addCollection(HashSet::new);
+
+        db.addCollection(LinkedHashSet::new);
+
+        db.addCollection(TreeSet::new);
+
+        db.addCollection(c -> {
+            Stack<Integer> s = new Stack<>();
+            s.addAll(c);
+            return s;
+        });
+
+        db.addCollection(PriorityQueue::new);
+
+        // ArrayDeque fails some tests since its fail-fast support is weaker
+        // than other collections and limited to detecting most, but not all,
+        // removals.  It probably requires its own test since it is difficult
+        // to abstract out the conditions under which it fails-fast.
+//        db.addCollection(ArrayDeque::new);
+
+        // Maps
+
+        db.addMap(HashMap::new);
+
+        db.addMap(LinkedHashMap::new);
+
+        // This fails when run through jtreg but passes when run through
+        // ant
+//        db.addMap(IdentityHashMap::new);
+
+        db.addMap(WeakHashMap::new);
+
+        // @@@  Descending maps etc
+        db.addMap(TreeMap::new);
+
+        return spliteratorDataProvider = data.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "Source")
+    public <T> void testTryAdvance(String description, Supplier<Source<T>> ss) {
+        {
+            Source<T> source = ss.get();
+            Spliterator<T> s = source.spliterator();
+
+            s.tryAdvance(e -> {
+            });
+            source.update();
+
+            executeAndCatch(() -> s.tryAdvance(e -> {
+            }));
+        }
+
+        {
+            Source<T> source = ss.get();
+            Spliterator<T> s = source.spliterator();
+
+            s.tryAdvance(e -> {
+            });
+            source.update();
+
+            executeAndCatch(() -> s.forEachRemaining(e -> {
+            }));
+        }
+    }
+
+    @Test(dataProvider = "Source")
+    public <T> void testForEach(String description, Supplier<Source<T>> ss) {
+        Source<T> source = ss.get();
+        Spliterator<T> s = source.spliterator();
+
+        executeAndCatch(() -> s.forEachRemaining(e -> {
+            source.update();
+        }));
+    }
+
+    @Test(dataProvider = "Source")
+    public <T> void testEstimateSize(String description, Supplier<Source<T>> ss) {
+        {
+            Source<T> source = ss.get();
+            Spliterator<T> s = source.spliterator();
+
+            s.estimateSize();
+            source.update();
+
+            executeAndCatch(() -> s.tryAdvance(e -> {
+            }));
+        }
+
+        {
+            Source<T> source = ss.get();
+            Spliterator<T> s = source.spliterator();
+
+            s.estimateSize();
+            source.update();
+
+            executeAndCatch(() -> s.forEachRemaining(e -> {
+            }));
+        }
+    }
+
+    private void executeAndCatch(Runnable r) {
+        executeAndCatch(ConcurrentModificationException.class, r);
+    }
+
+    private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
+        Exception caught = null;
+        try {
+            r.run();
+        }
+        catch (Exception e) {
+            caught = e;
+        }
+
+        assertNotNull(caught,
+                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
+                                    expected.getName()));
+        assertTrue(expected.isInstance(caught),
+                   String.format("Exception thrown %s not an instance of %s",
+                                 caught.getClass().getName(), expected.getName()));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastHelper.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,224 @@
+/*
+ * 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.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.RandomAccess;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+class SpliteratorLateBindingFailFastHelper {
+
+    interface Source<T> {
+        Spliterator<T> spliterator();
+
+        void update();
+
+        default boolean bindOnCharacteristics() {
+            return false;
+        }
+    }
+
+    static class IntSource<T> implements Source<Integer> {
+        final T b;
+        final Function<? super T, Spliterator.OfInt> toSpliterator;
+        final Consumer<T> updater;
+        final boolean bindOnCharacteristics;
+
+        public IntSource(T b, Function<? super T, Spliterator.OfInt> toSpliterator,
+                         Consumer<T> updater) {
+            this(b, toSpliterator, updater, false);
+        }
+
+        public IntSource(T b, Function<? super T, Spliterator.OfInt> toSpliterator,
+                         Consumer<T> updater, boolean bindOnCharacteristics) {
+            this.b = b;
+            this.toSpliterator = toSpliterator;
+            this.updater = updater;
+            this.bindOnCharacteristics = bindOnCharacteristics;
+        }
+
+        @Override
+        public Spliterator.OfInt spliterator() {
+            return toSpliterator.apply(b);
+        }
+
+        @Override
+        public void update() {
+            updater.accept(b);
+        }
+
+        @Override
+        public boolean bindOnCharacteristics() {
+            return bindOnCharacteristics;
+        }
+    }
+
+    static class SpliteratorDataBuilder<T> {
+        final List<Object[]> data;
+
+        final T newValue;
+
+        final List<T> exp;
+
+        final Map<T, T> mExp;
+
+        SpliteratorDataBuilder(List<Object[]> data, T newValue, List<T> exp) {
+            this.data = data;
+            this.newValue = newValue;
+            this.exp = exp;
+            this.mExp = createMap(exp);
+        }
+
+        Map<T, T> createMap(List<T> l) {
+            Map<T, T> m = new LinkedHashMap<>();
+            for (T t : l) {
+                m.put(t, t);
+            }
+            return m;
+        }
+
+        void add(String description, Supplier<Source<?>> s) {
+            data.add(new Object[]{description, s});
+        }
+
+        void addCollection(Function<Collection<T>, ? extends Collection<T>> f) {
+            class CollectionSource implements Source<T> {
+                final Collection<T> c = f.apply(exp);
+
+                final Consumer<Collection<T>> updater;
+
+                CollectionSource(Consumer<Collection<T>> updater) {
+                    this.updater = updater;
+                }
+
+                @Override
+                public Spliterator<T> spliterator() {
+                    return c.spliterator();
+                }
+
+                @Override
+                public void update() {
+                    updater.accept(c);
+                }
+            }
+
+            String description = "new " + f.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator() ";
+            add(description + "ADD", () -> new CollectionSource(c -> c.add(newValue)));
+            add(description + "REMOVE", () -> new CollectionSource(c -> c.remove(c.iterator().next())));
+        }
+
+        void addList(Function<Collection<T>, ? extends List<T>> l) {
+            addCollection(l);
+            addCollection(l.andThen(list -> list.subList(0, list.size())));
+        }
+
+        void addMap(Function<Map<T, T>, ? extends Map<T, T>> mapConstructor) {
+            class MapSource<U> implements Source<U> {
+                final Map<T, T> m = mapConstructor.apply(mExp);
+
+                final Collection<U> c;
+
+                final Consumer<Map<T, T>> updater;
+
+                MapSource(Function<Map<T, T>, Collection<U>> f, Consumer<Map<T, T>> updater) {
+                    this.c = f.apply(m);
+                    this.updater = updater;
+                }
+
+                @Override
+                public Spliterator<U> spliterator() {
+                    return c.spliterator();
+                }
+
+                @Override
+                public void update() {
+                    updater.accept(m);
+                }
+            }
+
+            Map<String, Consumer<Map<T, T>>> actions = new HashMap<>();
+            actions.put("ADD", m -> m.put(newValue, newValue));
+            actions.put("REMOVE", m -> m.remove(m.keySet().iterator().next()));
+
+            String description = "new " + mapConstructor.apply(Collections.<T, T>emptyMap()).getClass().getName();
+            for (Map.Entry<String, Consumer<Map<T, T>>> e : actions.entrySet()) {
+                add(description + ".keySet().spliterator() " + e.getKey(),
+                    () -> new MapSource<>(m -> m.keySet(), e.getValue()));
+                add(description + ".values().spliterator() " + e.getKey(),
+                    () -> new MapSource<>(m -> m.values(), e.getValue()));
+                add(description + ".entrySet().spliterator() " + e.getKey(),
+                    () -> new MapSource<>(m -> m.entrySet(), e.getValue()));
+            }
+        }
+    }
+
+    static class AbstractRandomAccessListImpl extends AbstractList<Integer> implements RandomAccess {
+        List<Integer> l;
+
+        AbstractRandomAccessListImpl(Collection<Integer> c) {
+            this.l = new ArrayList<>(c);
+        }
+
+        @Override
+        public boolean add(Integer integer) {
+            modCount++;
+            return l.add(integer);
+        }
+
+        @Override
+        public Iterator<Integer> iterator() {
+            return l.iterator();
+        }
+
+        @Override
+        public Integer get(int index) {
+            return l.get(index);
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            modCount++;
+            return l.remove(o);
+        }
+
+        @Override
+        public int size() {
+            return l.size();
+        }
+
+        @Override
+        public List<Integer> subList(int fromIndex, int toIndex) {
+            return l.subList(fromIndex, toIndex);
+        }
+    }
+}
--- a/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,401 +0,0 @@
-/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.PriorityQueue;
-import java.util.RandomAccess;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.Stack;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
-import java.util.WeakHashMap;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-import static org.testng.Assert.*;
-
-/**
- * @test
- * @bug 8148748
- * @summary Spliterator last-binding and fail-fast tests
- * @run testng SpliteratorLateBindingFailFastTest
- */
-
-@Test
-public class SpliteratorLateBindingFailFastTest {
-
-    private interface Source<T> {
-        Collection<T> asCollection();
-        void update();
-    }
-
-    private static class SpliteratorDataBuilder<T> {
-        final List<Object[]> data;
-
-        final T newValue;
-
-        final List<T> exp;
-
-        final Map<T, T> mExp;
-
-        SpliteratorDataBuilder(List<Object[]> data, T newValue, List<T> exp) {
-            this.data = data;
-            this.newValue = newValue;
-            this.exp = exp;
-            this.mExp = createMap(exp);
-        }
-
-        Map<T, T> createMap(List<T> l) {
-            Map<T, T> m = new LinkedHashMap<>();
-            for (T t : l) {
-                m.put(t, t);
-            }
-            return m;
-        }
-
-        void add(String description, Supplier<Source<?>> s) {
-            description = joiner(description).toString();
-            data.add(new Object[]{description, s});
-        }
-
-        void addCollection(Function<Collection<T>, ? extends Collection<T>> f) {
-            class CollectionSource implements Source<T> {
-                final Collection<T> c = f.apply(exp);
-
-                final Consumer<Collection<T>> updater;
-
-                CollectionSource(Consumer<Collection<T>> updater) {
-                    this.updater = updater;
-                }
-
-                @Override
-                public Collection<T> asCollection() {
-                    return c;
-                }
-
-                @Override
-                public void update() {
-                    updater.accept(c);
-                }
-            }
-
-            String description = "new " + f.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator() ";
-            add(description + "ADD", () -> new CollectionSource(c -> c.add(newValue)));
-            add(description + "REMOVE", () -> new CollectionSource(c -> c.remove(c.iterator().next())));
-        }
-
-        void addList(Function<Collection<T>, ? extends List<T>> l) {
-            addCollection(l);
-            addCollection(l.andThen(list -> list.subList(0, list.size())));
-        }
-
-        void addMap(Function<Map<T, T>, ? extends Map<T, T>> mapConstructor) {
-            class MapSource<U> implements Source<U> {
-                final Map<T, T> m = mapConstructor.apply(mExp);
-
-                final Collection<U> c;
-
-                final Consumer<Map<T, T>> updater;
-
-                MapSource(Function<Map<T, T>, Collection<U>> f, Consumer<Map<T, T>> updater) {
-                    this.c = f.apply(m);
-                    this.updater = updater;
-                }
-
-                @Override
-                public Collection<U> asCollection() {
-                    return c;
-                }
-
-                @Override
-                public void update() {
-                    updater.accept(m);
-                }
-            }
-
-            Map<String, Consumer<Map<T, T>>> actions = new HashMap<>();
-            actions.put("ADD", m -> m.put(newValue, newValue));
-            actions.put("REMOVE", m -> m.remove(m.keySet().iterator().next()));
-
-            String description = "new " + mapConstructor.apply(Collections.<T, T>emptyMap()).getClass().getName();
-            for (Map.Entry<String, Consumer<Map<T, T>>> e : actions.entrySet()) {
-                add(description + ".keySet().spliterator() " + e.getKey(),
-                    () -> new MapSource<T>(m -> m.keySet(), e.getValue()));
-                add(description + ".values().spliterator() " + e.getKey(),
-                    () -> new MapSource<T>(m -> m.values(), e.getValue()));
-                add(description + ".entrySet().spliterator() " + e.getKey(),
-                    () -> new MapSource<Map.Entry<T, T>>(m -> m.entrySet(), e.getValue()));
-            }
-        }
-
-        StringBuilder joiner(String description) {
-            return new StringBuilder(description).
-                    append(" {").
-                    append("size=").append(exp.size()).
-                    append("}");
-        }
-    }
-
-    static Object[][] spliteratorDataProvider;
-
-    @DataProvider(name = "Source")
-    public static Object[][] spliteratorDataProvider() {
-        if (spliteratorDataProvider != null) {
-            return spliteratorDataProvider;
-        }
-
-        List<Object[]> data = new ArrayList<>();
-        SpliteratorDataBuilder<Integer> db = new SpliteratorDataBuilder<>(data, 5, Arrays.asList(1, 2, 3, 4));
-
-        // Collections
-
-        db.addList(ArrayList::new);
-
-        db.addList(LinkedList::new);
-
-        db.addList(Vector::new);
-
-        class AbstractRandomAccessListImpl extends AbstractList<Integer> implements RandomAccess {
-            List<Integer> l;
-
-            AbstractRandomAccessListImpl(Collection<Integer> c) {
-                this.l = new ArrayList<>(c);
-            }
-
-            @Override
-            public boolean add(Integer integer) {
-                modCount++;
-                return l.add(integer);
-            }
-
-            @Override
-            public Iterator<Integer> iterator() {
-                return l.iterator();
-            }
-
-            @Override
-            public Integer get(int index) {
-                return l.get(index);
-            }
-
-            @Override
-            public boolean remove(Object o) {
-                modCount++;
-                return l.remove(o);
-            }
-
-            @Override
-            public int size() {
-                return l.size();
-            }
-
-            @Override
-            public List<Integer> subList(int fromIndex, int toIndex) {
-                return l.subList(fromIndex, toIndex);
-            }
-        }
-        db.addList(AbstractRandomAccessListImpl::new);
-
-        db.addCollection(HashSet::new);
-
-        db.addCollection(LinkedHashSet::new);
-
-        db.addCollection(TreeSet::new);
-
-
-        db.addCollection(c -> { Stack<Integer> s = new Stack<>(); s.addAll(c); return s;});
-
-        db.addCollection(PriorityQueue::new);
-
-        // ArrayDeque fails some tests since its fail-fast support is weaker
-        // than other collections and limited to detecting most, but not all,
-        // removals.  It probably requires its own test since it is difficult
-        // to abstract out the conditions under which it fails-fast.
-//        db.addCollection(ArrayDeque::new);
-
-        // Maps
-
-        db.addMap(HashMap::new);
-
-        db.addMap(LinkedHashMap::new);
-
-        // This fails when run through jtreg but passes when run through
-        // ant
-//        db.addMap(IdentityHashMap::new);
-
-        db.addMap(WeakHashMap::new);
-
-        // @@@  Descending maps etc
-        db.addMap(TreeMap::new);
-
-        return spliteratorDataProvider = data.toArray(new Object[0][]);
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void lateBindingTestWithForEach(String description, Supplier<Source<T>> ss) {
-        Source<T> source = ss.get();
-        Collection<T> c = source.asCollection();
-        Spliterator<T> s = c.spliterator();
-
-        source.update();
-
-        Set<T> r = new HashSet<>();
-        s.forEachRemaining(r::add);
-
-        assertEquals(r, new HashSet<>(c));
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void lateBindingTestWithTryAdvance(String description, Supplier<Source<T>> ss) {
-        Source<T> source = ss.get();
-        Collection<T> c = source.asCollection();
-        Spliterator<T> s = c.spliterator();
-
-        source.update();
-
-        Set<T> r = new HashSet<>();
-        while (s.tryAdvance(r::add)) { }
-
-        assertEquals(r, new HashSet<>(c));
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void lateBindingTestWithCharacteritics(String description, Supplier<Source<T>> ss) {
-        Source<T> source = ss.get();
-        Collection<T> c = source.asCollection();
-        Spliterator<T> s = c.spliterator();
-        s.characteristics();
-
-        Set<T> r = new HashSet<>();
-        s.forEachRemaining(r::add);
-
-        assertEquals(r, new HashSet<>(c));
-    }
-
-
-    @Test(dataProvider = "Source")
-    public <T> void testFailFastTestWithTryAdvance(String description, Supplier<Source<T>> ss) {
-        {
-            Source<T> source = ss.get();
-            Collection<T> c = source.asCollection();
-            Spliterator<T> s = c.spliterator();
-
-            s.tryAdvance(e -> {
-            });
-            source.update();
-
-            executeAndCatch(() -> s.tryAdvance(e -> { }));
-        }
-
-        {
-            Source<T> source = ss.get();
-            Collection<T> c = source.asCollection();
-            Spliterator<T> s = c.spliterator();
-
-            s.tryAdvance(e -> {
-            });
-            source.update();
-
-            executeAndCatch(() -> s.forEachRemaining(e -> {
-            }));
-        }
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void testFailFastTestWithForEach(String description, Supplier<Source<T>> ss) {
-        Source<T> source = ss.get();
-        Collection<T> c = source.asCollection();
-        Spliterator<T> s = c.spliterator();
-
-        executeAndCatch(() -> s.forEachRemaining(e -> {
-            source.update();
-        }));
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void testFailFastTestWithEstimateSize(String description, Supplier<Source<T>> ss) {
-        {
-            Source<T> source = ss.get();
-            Collection<T> c = source.asCollection();
-            Spliterator<T> s = c.spliterator();
-
-            s.estimateSize();
-            source.update();
-
-            executeAndCatch(() -> s.tryAdvance(e -> { }));
-        }
-
-        {
-            Source<T> source = ss.get();
-            Collection<T> c = source.asCollection();
-            Spliterator<T> s = c.spliterator();
-
-            s.estimateSize();
-            source.update();
-
-            executeAndCatch(() -> s.forEachRemaining(e -> {
-            }));
-        }
-    }
-
-    private void executeAndCatch(Runnable r) {
-        executeAndCatch(ConcurrentModificationException.class, r);
-    }
-
-    private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
-        Exception caught = null;
-        try {
-            r.run();
-        }
-        catch (Exception e) {
-            caught = e;
-        }
-
-        assertNotNull(caught,
-                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
-                                    expected.getName()));
-        assertTrue(expected.isInstance(caught),
-                   String.format("Exception thrown %s not an instance of %s",
-                                 caught.getClass().getName(), expected.getName()));
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Spliterator/SpliteratorLateBindingTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.nio.CharBuffer;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Stack;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+import java.util.WeakHashMap;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @test
+ * @bug 8148748 8170155
+ * @summary Spliterator last-binding tests
+ * @run testng SpliteratorLateBindingTest
+ */
+
+@Test
+public class SpliteratorLateBindingTest extends SpliteratorLateBindingFailFastHelper {
+
+    static Object[][] spliteratorDataProvider;
+
+    @DataProvider(name = "Source")
+    public static Object[][] sourceDataProvider() {
+        if (spliteratorDataProvider != null) {
+            return spliteratorDataProvider;
+        }
+
+        List<Object[]> data = new ArrayList<>();
+        SpliteratorDataBuilder<Integer> db =
+                new SpliteratorDataBuilder<>(data, 5, Arrays.asList(1, 2, 3, 4));
+
+        // Collections
+
+        db.addList(ArrayList::new);
+
+        db.addList(LinkedList::new);
+
+        db.addList(Vector::new);
+
+        db.addList(AbstractRandomAccessListImpl::new);
+
+        db.addCollection(HashSet::new);
+
+        db.addCollection(LinkedHashSet::new);
+
+        db.addCollection(TreeSet::new);
+
+        db.addCollection(c -> {
+            Stack<Integer> s = new Stack<>();
+            s.addAll(c);
+            return s;
+        });
+
+        db.addCollection(PriorityQueue::new);
+
+        db.addCollection(ArrayDeque::new);
+
+        // Maps
+
+        db.addMap(HashMap::new);
+
+        db.addMap(LinkedHashMap::new);
+
+        db.addMap(IdentityHashMap::new);
+
+        db.addMap(WeakHashMap::new);
+
+        // @@@  Descending maps etc
+        db.addMap(TreeMap::new);
+
+        // BitSet
+
+        List<Integer> bits = List.of(0, 1, 2);
+        Function<BitSet, Spliterator.OfInt> bitsSource = bs -> bs.stream().spliterator();
+        db.add("new BitSet.stream().spliterator() ADD",
+               () -> new IntSource<>(toBitSet(bits), bitsSource, bs -> bs.set(3)));
+        db.add("new BitSet.stream().spliterator() REMOVE",
+               () -> new IntSource<>(toBitSet(bits), bitsSource, bs -> bs.clear(2)));
+
+        // CharSequence
+
+        Function<CharSequence, Spliterator.OfInt> charsSource = sb -> sb.chars().spliterator();
+        Function<CharSequence, Spliterator.OfInt> pointsSource = sb -> sb.codePoints().spliterator();
+
+        db.add("new StringBuilder.chars().spliterator() ADD",
+               () -> new IntSource<>(new StringBuilder("ABC"), charsSource, bs -> bs.append("D"), true));
+        db.add("new StringBuilder.chars().spliterator() REMOVE",
+               () -> new IntSource<>(new StringBuilder("ABC"), charsSource, bs -> bs.deleteCharAt(2), true));
+        db.add("new StringBuilder.codePoints().spliterator() ADD",
+               () -> new IntSource<>(new StringBuilder("ABC"), pointsSource, bs -> bs.append("D"), true));
+        db.add("new StringBuilder.codePoints().spliterator() REMOVE",
+               () -> new IntSource<>(new StringBuilder("ABC"), pointsSource, bs -> bs.deleteCharAt(2), true));
+
+        db.add("new StringBuffer.chars().spliterator() ADD",
+               () -> new IntSource<>(new StringBuffer("ABC"), charsSource, bs -> bs.append("D"), true));
+        db.add("new StringBuffer.chars().spliterator() REMOVE",
+               () -> new IntSource<>(new StringBuffer("ABC"), charsSource, bs -> bs.deleteCharAt(2), true));
+        db.add("new StringBuffer.codePoints().spliterator() ADD",
+               () -> new IntSource<>(new StringBuffer("ABC"), pointsSource, bs -> bs.append("D"), true));
+        db.add("new StringBuffer.codePoints().spliterator() REMOVE",
+               () -> new IntSource<>(new StringBuffer("ABC"), pointsSource, bs -> bs.deleteCharAt(2), true));
+
+        db.add("CharBuffer.wrap().chars().spliterator() ADD",
+               () -> new IntSource<>(CharBuffer.wrap("ABCD").limit(3), charsSource, bs -> bs.limit(4), true));
+        db.add("CharBuffer.wrap().chars().spliterator() REMOVE",
+               () -> new IntSource<>(CharBuffer.wrap("ABCD"), charsSource, bs -> bs.limit(3), true));
+        db.add("CharBuffer.wrap().codePoints().spliterator() ADD",
+               () -> new IntSource<>(CharBuffer.wrap("ABCD").limit(3), pointsSource, bs -> bs.limit(4), true));
+        db.add("CharBuffer.wrap().codePoints().spliterator() REMOVE",
+               () -> new IntSource<>(CharBuffer.wrap("ABCD"), pointsSource, bs -> bs.limit(3), true));
+
+        return spliteratorDataProvider = data.toArray(new Object[0][]);
+    }
+
+
+    @DataProvider(name = "Source.Non.Binding.Characteristics")
+    public static Object[][] sourceCharacteristicsDataProvider() {
+        return Stream.of(sourceDataProvider()).filter(tc -> {
+            @SuppressWarnings("unchecked")
+            Supplier<Source<?>> s = (Supplier<Source<?>>) tc[1];
+            return !s.get().bindOnCharacteristics();
+        }).toArray(Object[][]::new);
+    }
+
+    static BitSet toBitSet(List<Integer> bits) {
+        BitSet bs = new BitSet();
+        bits.forEach(bs::set);
+        return bs;
+    }
+
+
+    @Test(dataProvider = "Source")
+    public <T> void testForEach(String description, Supplier<Source<T>> ss) {
+        Source<T> source = ss.get();
+        Spliterator<T> s = source.spliterator();
+
+        source.update();
+
+        Set<T> a = new HashSet<>();
+        s.forEachRemaining(a::add);
+
+        Set<T> e = new HashSet<>();
+        source.spliterator().forEachRemaining(e::add);
+        assertEquals(a, e);
+    }
+
+    @Test(dataProvider = "Source")
+    public <T> void testTryAdvance(String description, Supplier<Source<T>> ss) {
+        Source<T> source = ss.get();
+        Spliterator<T> s = source.spliterator();
+
+        source.update();
+
+        Set<T> a = new HashSet<>();
+        while (s.tryAdvance(a::add)) {
+        }
+
+        Set<T> e = new HashSet<>();
+        source.spliterator().forEachRemaining(e::add);
+        assertEquals(a, e);
+    }
+
+    @Test(dataProvider = "Source.Non.Binding.Characteristics")
+    public <T> void testCharacteristics(String description, Supplier<Source<T>> ss) {
+        Source<T> source = ss.get();
+        Spliterator<T> s = source.spliterator();
+
+        s.characteristics();
+        source.update();
+
+        Set<T> a = new HashSet<>();
+        s.forEachRemaining(a::add);
+
+        Set<T> e = new HashSet<>();
+        source.spliterator().forEachRemaining(e::add);
+        assertEquals(a, e);
+    }
+}
--- a/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -31,6 +31,7 @@
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import java.nio.CharBuffer;
 import java.util.AbstractCollection;
 import java.util.AbstractList;
 import java.util.AbstractSet;
@@ -884,6 +885,7 @@
             cdb.add("new CharSequenceImpl(\"%s\")", CharSequenceImpl::new);
             cdb.add("new StringBuilder(\"%s\")", StringBuilder::new);
             cdb.add("new StringBuffer(\"%s\")", StringBuffer::new);
+            cdb.add("CharBuffer.wrap(\"%s\".toCharArray())", s -> CharBuffer.wrap(s.toCharArray()));
         }
 
 
--- a/jdk/test/java/util/TreeMap/HeadTailTypeError.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/TreeMap/HeadTailTypeError.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,10 +22,10 @@
  */
 
 /*
-   @test
-   @bug 4251519 4251520
-   @summary indexOf and lastIndex of used to let you look outside the
-            valid range in the backing array
+ * @test
+ * @bug 4251519 4251520
+ * @summary indexOf and lastIndex of used to let you look outside the
+ *          valid range in the backing array
  */
 
 import java.util.*;
--- a/jdk/test/java/util/Vector/LastIndexOf.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/Vector/LastIndexOf.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,10 +22,10 @@
  */
 
 /*
-   @test
-   @bug 4271588
-   @summary Vector.lastIndex(Object, int) used to let you look outside the
-            valid range in the backing array
+ * @test
+ * @bug 4271588
+ * @summary Vector.lastIndex(Object, int) used to let you look outside the
+ *          valid range in the backing array
  */
 
 import java.util.*;
--- a/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java	Wed Jul 05 22:32:06 2017 +0200
@@ -42,23 +42,24 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Queue;
-import java.util.Random;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
 
 /*
  * @test
  * @bug 7014263
+ * @modules java.base/java.util.concurrent:open
  * @summary White box testing of ArrayBlockingQueue iterators.
  */
 
 /**
- * Highly coupled to the implementation of ArrayBlockingQueue.
+ * Tightly coupled to the implementation of ArrayBlockingQueue.
  * Uses reflection to inspect queue and iterator state.
  */
 @SuppressWarnings({"unchecked", "rawtypes"})
 public class IteratorConsistency {
-    final Random rnd = new Random();
+    final ThreadLocalRandom rnd = ThreadLocalRandom.current();
     final int CAPACITY = 20;
     Field itrsField;
     Field itemsField;
@@ -144,6 +145,10 @@
             check(!it.hasNext());
             check(isDetached(it));
         }
+        if (rnd.nextBoolean()) {
+            it.forEachRemaining(e -> { throw new AssertionError(); });
+            checkDetached(it);
+        }
         if (rnd.nextBoolean())
             try { it.next(); fail("should throw"); }
             catch (NoSuchElementException success) {}
--- a/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 6215625 7161229
+ * @modules java.base/java.util.concurrent:open
  * @summary Check correct behavior when last element is removed.
  * @author Martin Buchholz
  */
--- a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java	Wed Jul 05 22:32:06 2017 +0200
@@ -35,6 +35,8 @@
 /*
  * @test
  * @bug 6236036 6264015
+ * @modules java.base/java.util.concurrent:open
+ *          java.base/java.util.concurrent.locks:open
  * @summary Checks for a memory leak when a sequence of aborted timed
  * waits occur without a signal.  Uses the strategy of detecting
  * changes in the size of the object graph retained by a root object.
--- a/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,6 +34,8 @@
 /*
  * @test
  * @bug 8054446 8137184 8137185
+ * @modules java.base/java.util.concurrent:open
+ *          java.base/java.util.concurrent.locks:open
  * @summary Regression test for memory leak in remove(Object)
  */
 
--- a/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java	Wed Jul 05 22:32:06 2017 +0200
@@ -44,7 +44,6 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Queue;
-import java.util.Random;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentLinkedDeque;
@@ -52,10 +51,11 @@
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.ThreadLocalRandom;
 
 @SuppressWarnings({"unchecked", "rawtypes"})
 public class IteratorWeakConsistency {
-    final Random rnd = new Random();
+    final ThreadLocalRandom rnd = ThreadLocalRandom.current();
 
     void test(String[] args) throws Throwable {
         test(new LinkedBlockingQueue());
@@ -72,6 +72,9 @@
         if (rnd.nextBoolean()) {
             check(!it.hasNext());
         }
+        if (rnd.nextBoolean()) {
+            it.forEachRemaining(e -> { throw new AssertionError(); });
+        }
         if (rnd.nextBoolean())
             try { it.next(); fail("should throw"); }
             catch (NoSuchElementException success) {}
--- a/jdk/test/java/util/concurrent/FutureTask/Throw.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/FutureTask/Throw.java	Wed Jul 05 22:32:06 2017 +0200
@@ -140,8 +140,8 @@
             catch (Throwable t) {
                 if (k.isAssignableFrom(t.getClass())) pass();
                 else unexpected(t);}}
-    @SuppressWarnings("unchecked") static <T extends Throwable>
-        void uncheckedThrow(Throwable t) throws T {
+    @SuppressWarnings("unchecked")
+    static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
         throw (T)t; // rely on vacuous cast
     }
 }
--- a/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,6 +34,7 @@
 
 /*
  * @test
+ * @modules java.base/java.util.concurrent:open
  * @summary Test Phaser phase integer overflow behavior
  */
 
--- a/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java	Wed Jul 05 22:32:06 2017 +0200
@@ -36,6 +36,7 @@
  * @bug 8022642 8065320 8129861
  * @summary Ensure relative sanity when zero core threads
  * @library /lib/testlibrary/
+ * @modules java.base/java.util.concurrent:open
  */
 
 import static java.util.concurrent.TimeUnit.HOURS;
--- a/jdk/test/java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java	Wed Jul 05 22:32:06 2017 +0200
@@ -247,7 +247,13 @@
                tg.activeCount() > 0)
             Thread.sleep(4);
         equal(tg.activeCount(), 0);
-        check(System.nanoTime() - t0 >= tpe.getKeepAliveTime(NANOSECONDS));
+
+        // The following assertion is almost always true, but may
+        // exceptionally not be during a transition from core count
+        // too high to allowCoreThreadTimeOut.  Users will never
+        // notice, and we accept the small loss of testability.
+        //
+        // check(System.nanoTime() - t0 >= tpe.getKeepAliveTime(NANOSECONDS));
 
         //report("idle", tpe);
 
--- a/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java	Wed Jul 05 22:32:06 2017 +0200
@@ -290,8 +290,8 @@
         try {realMain(args);} catch (Throwable t) {unexpected(t);}
         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
-    @SuppressWarnings("unchecked") static <T extends Throwable>
-        void uncheckedThrow(Throwable t) throws T {
+    @SuppressWarnings("unchecked")
+    static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
         throw (T)t; // rely on vacuous cast
     }
 }
--- a/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 4992443 4994819
+ * @modules java.base/java.util.concurrent.atomic:open
  * @run main VMSupportsCS8
  * @summary Checks that the value of VMSupportsCS8 matches system properties.
  */
--- a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java	Wed Jul 05 22:32:06 2017 +0200
@@ -35,6 +35,7 @@
 /*
  * @test
  * @bug 8004138
+ * @modules java.base/java.util.concurrent:open
  * @summary Checks that ForkJoinTask thrown exceptions are not leaked.
  * This whitebox test is sensitive to forkjoin implementation details.
  */
--- a/jdk/test/java/util/concurrent/locks/Lock/FlakyMutex.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/locks/Lock/FlakyMutex.java	Wed Jul 05 22:32:06 2017 +0200
@@ -148,8 +148,8 @@
         try {realMain(args);} catch (Throwable t) {unexpected(t);}
         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
-    @SuppressWarnings("unchecked") static <T extends Throwable>
-        void uncheckedThrow(Throwable t) throws T {
+    @SuppressWarnings("unchecked")
+    static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
         throw (T)t; // rely on vacuous cast
     }
 }
--- a/jdk/test/java/util/concurrent/tck/ArrayBlockingQueueTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ArrayBlockingQueueTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,6 +38,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Queue;
@@ -46,45 +47,78 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 
 public class ArrayBlockingQueueTest extends JSR166TestCase {
 
-    public static class Fair extends BlockingQueueTest {
-        protected BlockingQueue emptyCollection() {
-            return new ArrayBlockingQueue(SIZE, true);
-        }
-    }
-
-    public static class NonFair extends BlockingQueueTest {
-        protected BlockingQueue emptyCollection() {
-            return new ArrayBlockingQueue(SIZE, false);
-        }
-    }
-
     public static void main(String[] args) {
         main(suite(), args);
     }
 
     public static Test suite() {
-        return newTestSuite(ArrayBlockingQueueTest.class,
-                            new Fair().testSuite(),
-                            new NonFair().testSuite());
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ArrayBlockingQueue.class; }
+            public Collection emptyCollection() {
+                boolean fair = ThreadLocalRandom.current().nextBoolean();
+                return populatedQueue(0, SIZE, 2 * SIZE, fair);
+            }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
+
+        return newTestSuite(
+            ArrayBlockingQueueTest.class,
+            new Fair().testSuite(),
+            new NonFair().testSuite(),
+            CollectionTest.testSuite(new Implementation()));
+    }
+
+    public static class Fair extends BlockingQueueTest {
+        protected BlockingQueue emptyCollection() {
+            return populatedQueue(0, SIZE, 2 * SIZE, true);
+        }
+    }
+
+    public static class NonFair extends BlockingQueueTest {
+        protected BlockingQueue emptyCollection() {
+            return populatedQueue(0, SIZE, 2 * SIZE, false);
+        }
     }
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
-    private ArrayBlockingQueue<Integer> populatedQueue(int n) {
-        ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<Integer>(n);
+    static ArrayBlockingQueue<Integer> populatedQueue(int n) {
+        return populatedQueue(n, n, n, false);
+    }
+
+    /**
+     * Returns a new queue of given size containing consecutive
+     * Integers 0 ... n - 1, with given capacity range and fairness.
+     */
+    static ArrayBlockingQueue<Integer> populatedQueue(
+        int size, int minCapacity, int maxCapacity, boolean fair) {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int capacity = rnd.nextInt(minCapacity, maxCapacity + 1);
+        ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<>(capacity);
         assertTrue(q.isEmpty());
-        for (int i = 0; i < n; i++)
-            assertTrue(q.offer(new Integer(i)));
-        assertFalse(q.isEmpty());
-        assertEquals(0, q.remainingCapacity());
-        assertEquals(n, q.size());
+        // shuffle circular array elements so they wrap
+        {
+            int n = rnd.nextInt(capacity);
+            for (int i = 0; i < n; i++) q.add(42);
+            for (int i = 0; i < n; i++) q.remove();
+        }
+        for (int i = 0; i < size; i++)
+            assertTrue(q.offer((Integer) i));
+        assertEquals(size == 0, q.isEmpty());
+        assertEquals(capacity - size, q.remainingCapacity());
+        assertEquals(size, q.size());
+        if (size > 0)
+            assertEquals((Integer) 0, q.peek());
         return q;
     }
 
@@ -98,17 +132,25 @@
     /**
      * Constructor throws IAE if capacity argument nonpositive
      */
-    public void testConstructor2() {
-        try {
-            new ArrayBlockingQueue(0);
-            shouldThrow();
-        } catch (IllegalArgumentException success) {}
+    public void testConstructor_nonPositiveCapacity() {
+        for (int i : new int[] { 0, -1, Integer.MIN_VALUE }) {
+            try {
+                new ArrayBlockingQueue(i);
+                shouldThrow();
+            } catch (IllegalArgumentException success) {}
+            for (boolean fair : new boolean[] { true, false }) {
+                try {
+                    new ArrayBlockingQueue(i, fair);
+                    shouldThrow();
+                } catch (IllegalArgumentException success) {}
+            }
+        }
     }
 
     /**
      * Initializing from null Collection throws NPE
      */
-    public void testConstructor3() {
+    public void testConstructor_nullCollection() {
         try {
             new ArrayBlockingQueue(1, true, null);
             shouldThrow();
@@ -143,13 +185,13 @@
     /**
      * Initializing from too large collection throws IAE
      */
-    public void testConstructor6() {
-        Integer[] ints = new Integer[SIZE];
-        for (int i = 0; i < SIZE; ++i)
-            ints[i] = i;
-        Collection<Integer> elements = Arrays.asList(ints);
+    public void testConstructor_collectionTooLarge() {
+        // just barely fits - succeeds
+        new ArrayBlockingQueue(SIZE, false,
+                               Collections.nCopies(SIZE, ""));
         try {
-            new ArrayBlockingQueue(SIZE - 1, false, elements);
+            new ArrayBlockingQueue(SIZE - 1, false,
+                                   Collections.nCopies(SIZE, ""));
             shouldThrow();
         } catch (IllegalArgumentException success) {}
     }
@@ -171,12 +213,12 @@
      * Queue transitions from empty to full when elements added
      */
     public void testEmptyFull() {
-        ArrayBlockingQueue q = new ArrayBlockingQueue(2);
+        BlockingQueue q = populatedQueue(0, 2, 2, false);
         assertTrue(q.isEmpty());
         assertEquals(2, q.remainingCapacity());
         q.add(one);
         assertFalse(q.isEmpty());
-        q.add(two);
+        assertTrue(q.offer(two));
         assertFalse(q.isEmpty());
         assertEquals(0, q.remainingCapacity());
         assertFalse(q.offer(three));
@@ -186,15 +228,18 @@
      * remainingCapacity decreases on add, increases on remove
      */
     public void testRemainingCapacity() {
-        BlockingQueue q = populatedQueue(SIZE);
-        for (int i = 0; i < SIZE; ++i) {
-            assertEquals(i, q.remainingCapacity());
-            assertEquals(SIZE, q.size() + q.remainingCapacity());
+        int size = ThreadLocalRandom.current().nextInt(1, SIZE);
+        BlockingQueue q = populatedQueue(size, size, 2 * size, false);
+        int spare = q.remainingCapacity();
+        int capacity = spare + size;
+        for (int i = 0; i < size; i++) {
+            assertEquals(spare + i, q.remainingCapacity());
+            assertEquals(capacity, q.size() + q.remainingCapacity());
             assertEquals(i, q.remove());
         }
-        for (int i = 0; i < SIZE; ++i) {
-            assertEquals(SIZE - i, q.remainingCapacity());
-            assertEquals(SIZE, q.size() + q.remainingCapacity());
+        for (int i = 0; i < size; i++) {
+            assertEquals(capacity - i, q.remainingCapacity());
+            assertEquals(capacity, q.size() + q.remainingCapacity());
             assertTrue(q.add(i));
         }
     }
@@ -213,12 +258,10 @@
      */
     public void testAdd() {
         ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
-        for (int i = 0; i < SIZE; ++i) {
-            assertTrue(q.add(new Integer(i)));
-        }
+        for (int i = 0; i < SIZE; i++) assertTrue(q.add((Integer) i));
         assertEquals(0, q.remainingCapacity());
         try {
-            q.add(new Integer(SIZE));
+            q.add((Integer) SIZE);
             shouldThrow();
         } catch (IllegalStateException success) {}
     }
@@ -252,13 +295,17 @@
     /**
      * addAll throws ISE if not enough room
      */
-    public void testAddAll4() {
-        ArrayBlockingQueue q = new ArrayBlockingQueue(1);
-        Integer[] ints = new Integer[SIZE];
-        for (int i = 0; i < SIZE; ++i)
-            ints[i] = new Integer(i);
+    public void testAddAll_insufficientSpace() {
+        int size = ThreadLocalRandom.current().nextInt(1, SIZE);
+        ArrayBlockingQueue q = populatedQueue(0, size, size, false);
+        // Just fits:
+        q.addAll(populatedQueue(size, size, 2 * size, false));
+        assertEquals(0, q.remainingCapacity());
+        assertEquals(size, q.size());
+        assertEquals(0, q.peek());
         try {
-            q.addAll(Arrays.asList(ints));
+            q = populatedQueue(0, size, size, false);
+            q.addAll(Collections.nCopies(size + 1, 42));
             shouldThrow();
         } catch (IllegalStateException success) {}
     }
@@ -545,8 +592,10 @@
      * contains(x) reports true when elements added but not yet removed
      */
     public void testContains() {
-        ArrayBlockingQueue q = populatedQueue(SIZE);
-        for (int i = 0; i < SIZE; ++i) {
+        int size = ThreadLocalRandom.current().nextInt(1, SIZE);
+        ArrayBlockingQueue q = populatedQueue(size, size, 2 * size, false);
+        assertFalse(q.contains(null));
+        for (int i = 0; i < size; ++i) {
             assertTrue(q.contains(new Integer(i)));
             assertEquals(i, q.poll());
             assertFalse(q.contains(new Integer(i)));
@@ -557,11 +606,13 @@
      * clear removes all elements
      */
     public void testClear() {
-        ArrayBlockingQueue q = populatedQueue(SIZE);
+        int size = ThreadLocalRandom.current().nextInt(1, 5);
+        ArrayBlockingQueue q = populatedQueue(size, size, 2 * size, false);
+        int capacity = size + q.remainingCapacity();
         q.clear();
         assertTrue(q.isEmpty());
         assertEquals(0, q.size());
-        assertEquals(SIZE, q.remainingCapacity());
+        assertEquals(capacity, q.remainingCapacity());
         q.add(one);
         assertFalse(q.isEmpty());
         assertTrue(q.contains(one));
@@ -618,103 +669,75 @@
         }
     }
 
-    void checkToArray(ArrayBlockingQueue q) {
+    void checkToArray(ArrayBlockingQueue<Integer> q) {
         int size = q.size();
-        Object[] o = q.toArray();
-        assertEquals(size, o.length);
+        Object[] a1 = q.toArray();
+        assertEquals(size, a1.length);
+        Integer[] a2 = q.toArray(new Integer[0]);
+        assertEquals(size, a2.length);
+        Integer[] a3 = q.toArray(new Integer[Math.max(0, size - 1)]);
+        assertEquals(size, a3.length);
+        Integer[] a4 = new Integer[size];
+        assertSame(a4, q.toArray(a4));
+        Integer[] a5 = new Integer[size + 1];
+        Arrays.fill(a5, 42);
+        assertSame(a5, q.toArray(a5));
+        Integer[] a6 = new Integer[size + 2];
+        Arrays.fill(a6, 42);
+        assertSame(a6, q.toArray(a6));
+        Object[][] as = { a1, a2, a3, a4, a5, a6 };
+        for (Object[] a : as) {
+            if (a.length > size) assertNull(a[size]);
+            if (a.length > size + 1) assertEquals(42, a[size + 1]);
+        }
         Iterator it = q.iterator();
+        Integer s = q.peek();
         for (int i = 0; i < size; i++) {
             Integer x = (Integer) it.next();
-            assertEquals((Integer)o[0] + i, (int) x);
-            assertSame(o[i], x);
+            assertEquals(s + i, (int) x);
+            for (Object[] a : as)
+                assertSame(a1[i], x);
         }
     }
 
     /**
-     * toArray() contains all elements in FIFO order
+     * toArray() and toArray(a) contain all elements in FIFO order
      */
     public void testToArray() {
-        ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
-        for (int i = 0; i < SIZE; i++) {
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        final int size = rnd.nextInt(6);
+        final int capacity = Math.max(1, size + rnd.nextInt(size + 1));
+        ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<>(capacity);
+        for (int i = 0; i < size; i++) {
             checkToArray(q);
             q.add(i);
         }
         // Provoke wraparound
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray(q);
-            assertEquals(i, q.poll());
+        int added = size * 2;
+        for (int i = 0; i < added; i++) {
             checkToArray(q);
-            q.add(SIZE + i);
-        }
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray(q);
-            assertEquals(SIZE + i, q.poll());
+            assertEquals((Integer) i, q.poll());
+            q.add(size + i);
         }
-    }
-
-    void checkToArray2(ArrayBlockingQueue q) {
-        int size = q.size();
-        Integer[] a1 = (size == 0) ? null : new Integer[size - 1];
-        Integer[] a2 = new Integer[size];
-        Integer[] a3 = new Integer[size + 2];
-        if (size > 0) Arrays.fill(a1, 42);
-        Arrays.fill(a2, 42);
-        Arrays.fill(a3, 42);
-        Integer[] b1 = (size == 0) ? null : (Integer[]) q.toArray(a1);
-        Integer[] b2 = (Integer[]) q.toArray(a2);
-        Integer[] b3 = (Integer[]) q.toArray(a3);
-        assertSame(a2, b2);
-        assertSame(a3, b3);
-        Iterator it = q.iterator();
         for (int i = 0; i < size; i++) {
-            Integer x = (Integer) it.next();
-            assertSame(b1[i], x);
-            assertEquals(b1[0] + i, (int) x);
-            assertSame(b2[i], x);
-            assertSame(b3[i], x);
-        }
-        assertNull(a3[size]);
-        assertEquals(42, (int) a3[size + 1]);
-        if (size > 0) {
-            assertNotSame(a1, b1);
-            assertEquals(size, b1.length);
-            for (int i = 0; i < a1.length; i++) {
-                assertEquals(42, (int) a1[i]);
-            }
-        }
-    }
-
-    /**
-     * toArray(a) contains all elements in FIFO order
-     */
-    public void testToArray2() {
-        ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            q.add(i);
-        }
-        // Provoke wraparound
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            assertEquals(i, q.poll());
-            checkToArray2(q);
-            q.add(SIZE + i);
-        }
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            assertEquals(SIZE + i, q.poll());
+            checkToArray(q);
+            assertEquals((Integer) (added + i), q.poll());
         }
     }
 
     /**
      * toArray(incompatible array type) throws ArrayStoreException
      */
-    public void testToArray1_BadArg() {
+    public void testToArray_incompatibleArrayType() {
         ArrayBlockingQueue q = populatedQueue(SIZE);
         try {
             q.toArray(new String[10]);
             shouldThrow();
         } catch (ArrayStoreException success) {}
+        try {
+            q.toArray(new String[0]);
+            shouldThrow();
+        } catch (ArrayStoreException success) {}
     }
 
     /**
@@ -943,8 +966,8 @@
      */
     public void testNeverContainsNull() {
         Collection<?>[] qs = {
-            new ArrayBlockingQueue<Object>(10),
-            populatedQueue(2),
+            populatedQueue(0, 1, 10, false),
+            populatedQueue(2, 2, 10, true),
         };
 
         for (Collection<?> q : qs) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/ArrayDeque8Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,125 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Spliterator;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class ArrayDeque8Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        return newTestSuite(ArrayDeque8Test.class);
+    }
+
+    /**
+     * Spliterator.getComparator always throws IllegalStateException
+     */
+    public void testSpliterator_getComparator() {
+        assertThrows(IllegalStateException.class,
+                     () -> new ArrayDeque().spliterator().getComparator());
+    }
+
+    /**
+     * Spliterator characteristics are as advertised
+     */
+    public void testSpliterator_characteristics() {
+        ArrayDeque q = new ArrayDeque();
+        Spliterator s = q.spliterator();
+        int characteristics = s.characteristics();
+        int required = Spliterator.NONNULL
+            | Spliterator.ORDERED
+            | Spliterator.SIZED
+            | Spliterator.SUBSIZED;
+        assertEquals(required, characteristics & required);
+        assertTrue(s.hasCharacteristics(required));
+        assertEquals(0, characteristics
+                     & (Spliterator.CONCURRENT
+                        | Spliterator.DISTINCT
+                        | Spliterator.IMMUTABLE
+                        | Spliterator.SORTED));
+    }
+
+    /**
+     * Handle capacities near Integer.MAX_VALUE.
+     * ant -Dvmoptions='-Xms28g -Xmx28g' -Djsr166.expensiveTests=true -Djsr166.tckTestClass=ArrayDeque8Test -Djsr166.methodFilter=testHugeCapacity tck
+     */
+    public void testHugeCapacity() {
+        if (! (testImplementationDetails
+               && expensiveTests
+               && Runtime.getRuntime().maxMemory() > 24L * (1 << 30)))
+            return;
+
+        final Integer e = 42;
+        final int maxArraySize = Integer.MAX_VALUE - 8;
+
+        assertThrows(OutOfMemoryError.class,
+                     () -> new ArrayDeque(Integer.MAX_VALUE));
+
+        {
+            ArrayDeque q = new ArrayDeque(maxArraySize - 1);
+            assertEquals(0, q.size());
+            assertTrue(q.isEmpty());
+            q = null;
+        }
+
+        {
+            ArrayDeque q = new ArrayDeque();
+            assertTrue(q.addAll(Collections.nCopies(maxArraySize - 3, e)));
+            assertEquals(e, q.peekFirst());
+            assertEquals(e, q.peekLast());
+            assertEquals(maxArraySize - 3, q.size());
+            q.addFirst((Integer) 0);
+            q.addLast((Integer) 1);
+            assertEquals((Integer) 0, q.peekFirst());
+            assertEquals((Integer) 1, q.peekLast());
+            assertEquals(maxArraySize - 1, q.size());
+
+            ArrayDeque qq = q;
+            ArrayDeque smallish = new ArrayDeque(
+                Collections.nCopies(Integer.MAX_VALUE - q.size() + 1, e));
+            assertThrows(
+                IllegalStateException.class,
+                () -> qq.addAll(qq),
+                () -> qq.addAll(smallish),
+                () -> smallish.addAll(qq));
+        }
+    }
+
+}
--- a/jdk/test/java/util/concurrent/tck/ArrayDequeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ArrayDequeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,19 +26,22 @@
  * However, the following notice accompanied the original version of this
  * file:
  *
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Queue;
 import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -49,20 +52,60 @@
     }
 
     public static Test suite() {
-        return new TestSuite(ArrayDequeTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ArrayDeque.class; }
+            public Collection emptyCollection() { return populatedDeque(0); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return false; }
+        }
+        return newTestSuite(ArrayDequeTest.class,
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new deque of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
-    private ArrayDeque<Integer> populatedDeque(int n) {
-        ArrayDeque<Integer> q = new ArrayDeque<Integer>();
+    private static ArrayDeque<Integer> populatedDeque(int n) {
+        // Randomize various aspects of memory layout, including
+        // capacity slop and wraparound.
+        final ArrayDeque<Integer> q;
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        switch (rnd.nextInt(6)) {
+        case 0: q = new ArrayDeque<Integer>();      break;
+        case 1: q = new ArrayDeque<Integer>(0);     break;
+        case 2: q = new ArrayDeque<Integer>(1);     break;
+        case 3: q = new ArrayDeque<Integer>(Math.max(0, n - 1)); break;
+        case 4: q = new ArrayDeque<Integer>(n);     break;
+        case 5: q = new ArrayDeque<Integer>(n + 1); break;
+        default: throw new AssertionError();
+        }
+        switch (rnd.nextInt(3)) {
+        case 0:
+            q.addFirst(42);
+            assertEquals((Integer) 42, q.removeLast());
+            break;
+        case 1:
+            q.addLast(42);
+            assertEquals((Integer) 42, q.removeFirst());
+            break;
+        case 2: /* do nothing */ break;
+        default: throw new AssertionError();
+        }
         assertTrue(q.isEmpty());
-        for (int i = 0; i < n; ++i)
-            assertTrue(q.offerLast(new Integer(i)));
-        assertFalse(q.isEmpty());
+        if (rnd.nextBoolean())
+            for (int i = 0; i < n; i++)
+                assertTrue(q.offerLast((Integer) i));
+        else
+            for (int i = n; --i >= 0; )
+                q.addFirst((Integer) i);
         assertEquals(n, q.size());
+        if (n > 0) {
+            assertFalse(q.isEmpty());
+            assertEquals((Integer) 0, q.peekFirst());
+            assertEquals((Integer) (n - 1), q.peekLast());
+        }
         return q;
     }
 
@@ -556,30 +599,48 @@
      * removeFirstOccurrence(x) removes x and returns true if present
      */
     public void testRemoveFirstOccurrence() {
-        ArrayDeque q = populatedDeque(SIZE);
+        Deque<Integer> q = populatedDeque(SIZE);
+        assertFalse(q.removeFirstOccurrence(null));
         for (int i = 1; i < SIZE; i += 2) {
-            assertTrue(q.removeFirstOccurrence(new Integer(i)));
+            assertTrue(q.removeFirstOccurrence(i));
+            assertFalse(q.contains(i));
         }
         for (int i = 0; i < SIZE; i += 2) {
-            assertTrue(q.removeFirstOccurrence(new Integer(i)));
-            assertFalse(q.removeFirstOccurrence(new Integer(i + 1)));
+            assertTrue(q.removeFirstOccurrence(i));
+            assertFalse(q.removeFirstOccurrence(i + 1));
+            assertFalse(q.contains(i));
+            assertFalse(q.contains(i + 1));
         }
         assertTrue(q.isEmpty());
+        assertFalse(q.removeFirstOccurrence(null));
+        assertFalse(q.removeFirstOccurrence(42));
+        q = new ArrayDeque();
+        assertFalse(q.removeFirstOccurrence(null));
+        assertFalse(q.removeFirstOccurrence(42));
     }
 
     /**
      * removeLastOccurrence(x) removes x and returns true if present
      */
     public void testRemoveLastOccurrence() {
-        ArrayDeque q = populatedDeque(SIZE);
+        Deque<Integer> q = populatedDeque(SIZE);
+        assertFalse(q.removeLastOccurrence(null));
         for (int i = 1; i < SIZE; i += 2) {
-            assertTrue(q.removeLastOccurrence(new Integer(i)));
+            assertTrue(q.removeLastOccurrence(i));
+            assertFalse(q.contains(i));
         }
         for (int i = 0; i < SIZE; i += 2) {
-            assertTrue(q.removeLastOccurrence(new Integer(i)));
-            assertFalse(q.removeLastOccurrence(new Integer(i + 1)));
+            assertTrue(q.removeLastOccurrence(i));
+            assertFalse(q.removeLastOccurrence(i + 1));
+            assertFalse(q.contains(i));
+            assertFalse(q.contains(i + 1));
         }
         assertTrue(q.isEmpty());
+        assertFalse(q.removeLastOccurrence(null));
+        assertFalse(q.removeLastOccurrence(42));
+        q = new ArrayDeque();
+        assertFalse(q.removeLastOccurrence(null));
+        assertFalse(q.removeLastOccurrence(42));
     }
 
     /**
@@ -652,89 +713,57 @@
         }
     }
 
-    void checkToArray(ArrayDeque q) {
+    void checkToArray(ArrayDeque<Integer> q) {
         int size = q.size();
-        Object[] o = q.toArray();
-        assertEquals(size, o.length);
+        Object[] a1 = q.toArray();
+        assertEquals(size, a1.length);
+        Integer[] a2 = q.toArray(new Integer[0]);
+        assertEquals(size, a2.length);
+        Integer[] a3 = q.toArray(new Integer[Math.max(0, size - 1)]);
+        assertEquals(size, a3.length);
+        Integer[] a4 = new Integer[size];
+        assertSame(a4, q.toArray(a4));
+        Integer[] a5 = new Integer[size + 1];
+        Arrays.fill(a5, 42);
+        assertSame(a5, q.toArray(a5));
+        Integer[] a6 = new Integer[size + 2];
+        Arrays.fill(a6, 42);
+        assertSame(a6, q.toArray(a6));
+        Object[][] as = { a1, a2, a3, a4, a5, a6 };
+        for (Object[] a : as) {
+            if (a.length > size) assertNull(a[size]);
+            if (a.length > size + 1) assertEquals(42, a[size + 1]);
+        }
         Iterator it = q.iterator();
+        Integer s = q.peekFirst();
         for (int i = 0; i < size; i++) {
             Integer x = (Integer) it.next();
-            assertEquals((Integer)o[0] + i, (int) x);
-            assertSame(o[i], x);
+            assertEquals(s + i, (int) x);
+            for (Object[] a : as)
+                assertSame(a1[i], x);
         }
     }
 
     /**
-     * toArray() contains all elements in FIFO order
+     * toArray() and toArray(a) contain all elements in FIFO order
      */
     public void testToArray() {
-        ArrayDeque q = new ArrayDeque();
-        for (int i = 0; i < SIZE; i++) {
+        final int size = ThreadLocalRandom.current().nextInt(10);
+        ArrayDeque<Integer> q = new ArrayDeque<>(size);
+        for (int i = 0; i < size; i++) {
             checkToArray(q);
             q.addLast(i);
         }
         // Provoke wraparound
-        for (int i = 0; i < SIZE; i++) {
+        int added = size * 2;
+        for (int i = 0; i < added; i++) {
             checkToArray(q);
-            assertEquals(i, q.poll());
-            q.addLast(SIZE + i);
-        }
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray(q);
-            assertEquals(SIZE + i, q.poll());
+            assertEquals((Integer) i, q.poll());
+            q.addLast(size + i);
         }
-    }
-
-    void checkToArray2(ArrayDeque q) {
-        int size = q.size();
-        Integer[] a1 = (size == 0) ? null : new Integer[size - 1];
-        Integer[] a2 = new Integer[size];
-        Integer[] a3 = new Integer[size + 2];
-        if (size > 0) Arrays.fill(a1, 42);
-        Arrays.fill(a2, 42);
-        Arrays.fill(a3, 42);
-        Integer[] b1 = (size == 0) ? null : (Integer[]) q.toArray(a1);
-        Integer[] b2 = (Integer[]) q.toArray(a2);
-        Integer[] b3 = (Integer[]) q.toArray(a3);
-        assertSame(a2, b2);
-        assertSame(a3, b3);
-        Iterator it = q.iterator();
         for (int i = 0; i < size; i++) {
-            Integer x = (Integer) it.next();
-            assertSame(b1[i], x);
-            assertEquals(b1[0] + i, (int) x);
-            assertSame(b2[i], x);
-            assertSame(b3[i], x);
-        }
-        assertNull(a3[size]);
-        assertEquals(42, (int) a3[size + 1]);
-        if (size > 0) {
-            assertNotSame(a1, b1);
-            assertEquals(size, b1.length);
-            for (int i = 0; i < a1.length; i++) {
-                assertEquals(42, (int) a1[i]);
-            }
-        }
-    }
-
-    /**
-     * toArray(a) contains all elements in FIFO order
-     */
-    public void testToArray2() {
-        ArrayDeque q = new ArrayDeque();
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            q.addLast(i);
-        }
-        // Provoke wraparound
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            assertEquals(i, q.poll());
-            q.addLast(SIZE + i);
-        }
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            assertEquals(SIZE + i, q.poll());
+            checkToArray(q);
+            assertEquals((Integer) (added + i), q.poll());
         }
     }
 
@@ -753,13 +782,17 @@
     /**
      * toArray(incompatible array type) throws ArrayStoreException
      */
-    public void testToArray1_BadArg() {
+    public void testToArray_incompatibleArrayType() {
         ArrayDeque l = new ArrayDeque();
         l.add(new Integer(5));
         try {
             l.toArray(new String[10]);
             shouldThrow();
         } catch (ArrayStoreException success) {}
+        try {
+            l.toArray(new String[0]);
+            shouldThrow();
+        } catch (ArrayStoreException success) {}
     }
 
     /**
@@ -917,6 +950,25 @@
         assertNotSame(y, x);
         assertEquals(x.size(), y.size());
         assertEquals(x.toString(), y.toString());
+        assertEquals(Arrays.toString(x.toArray()), Arrays.toString(y.toArray()));
+        assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+        while (!x.isEmpty()) {
+            assertFalse(y.isEmpty());
+            assertEquals(x.remove(), y.remove());
+        }
+        assertTrue(y.isEmpty());
+    }
+
+    /**
+     * A cloned deque has same elements in same order
+     */
+    public void testClone() throws Exception {
+        ArrayDeque<Integer> x = populatedDeque(SIZE);
+        ArrayDeque<Integer> y = x.clone();
+
+        assertNotSame(y, x);
+        assertEquals(x.size(), y.size());
+        assertEquals(x.toString(), y.toString());
         assertTrue(Arrays.equals(x.toArray(), y.toArray()));
         while (!x.isEmpty()) {
             assertFalse(y.isEmpty());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/ArrayListTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class ArrayListTest extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ArrayList.class; }
+            public List emptyCollection() { return new ArrayList(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return true; }
+        }
+        class SubListImplementation extends Implementation {
+            public List emptyCollection() {
+                return super.emptyCollection().subList(0, 0);
+            }
+        }
+        return newTestSuite(
+                // ArrayListTest.class,
+                CollectionTest.testSuite(new Implementation()),
+                CollectionTest.testSuite(new SubListImplementation()));
+    }
+
+}
--- a/jdk/test/java/util/concurrent/tck/Atomic8Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/Atomic8Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -45,6 +45,9 @@
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
+/**
+ * Tests of atomic class methods accepting lambdas introduced in JDK8.
+ */
 public class Atomic8Test extends JSR166TestCase {
 
     public static void main(String[] args) {
@@ -54,30 +57,25 @@
         return new TestSuite(Atomic8Test.class);
     }
 
-    /*
-     * Tests of atomic class methods accepting lambdas
-     * introduced in JDK8.
-     */
-
     static long addLong17(long x) { return x + 17; }
     static int addInt17(int x) { return x + 17; }
     static Integer addInteger17(Integer x) {
-        return new Integer(x.intValue() + 17);
+        return x.intValue() + 17;
     }
     static Integer sumInteger(Integer x, Integer y) {
-        return new Integer(x.intValue() + y.intValue());
+        return x.intValue() + y.intValue();
     }
 
     volatile long aLongField;
     volatile int anIntField;
     volatile Integer anIntegerField;
 
-    AtomicLongFieldUpdater aLongFieldUpdater() {
+    AtomicLongFieldUpdater<Atomic8Test> aLongFieldUpdater() {
         return AtomicLongFieldUpdater.newUpdater
             (Atomic8Test.class, "aLongField");
     }
 
-    AtomicIntegerFieldUpdater anIntFieldUpdater() {
+    AtomicIntegerFieldUpdater<Atomic8Test> anIntFieldUpdater() {
         return AtomicIntegerFieldUpdater.newUpdater
             (Atomic8Test.class, "anIntField");
     }
@@ -180,9 +178,9 @@
      */
     public void testReferenceGetAndUpdate() {
         AtomicReference<Integer> a = new AtomicReference<>(one);
-        assertEquals(new Integer(1), a.getAndUpdate(Atomic8Test::addInteger17));
-        assertEquals(new Integer(18), a.getAndUpdate(Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get());
+        assertEquals((Integer) 1, a.getAndUpdate(Atomic8Test::addInteger17));
+        assertEquals((Integer) 18, a.getAndUpdate(Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get());
     }
 
     /**
@@ -191,9 +189,9 @@
      */
     public void testReferenceUpdateAndGet() {
         AtomicReference<Integer> a = new AtomicReference<>(one);
-        assertEquals(new Integer(18), a.updateAndGet(Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.updateAndGet(Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get());
+        assertEquals((Integer) 18, a.updateAndGet(Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.updateAndGet(Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get());
     }
 
     /**
@@ -202,9 +200,9 @@
      */
     public void testReferenceGetAndAccumulate() {
         AtomicReference<Integer> a = new AtomicReference<>(one);
-        assertEquals(new Integer(1), a.getAndAccumulate(2, Atomic8Test::sumInteger));
-        assertEquals(new Integer(3), a.getAndAccumulate(3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(6), a.get());
+        assertEquals((Integer) 1, a.getAndAccumulate(2, Atomic8Test::sumInteger));
+        assertEquals((Integer) 3, a.getAndAccumulate(3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 6, a.get());
     }
 
     /**
@@ -213,9 +211,9 @@
      */
     public void testReferenceAccumulateAndGet() {
         AtomicReference<Integer> a = new AtomicReference<>(one);
-        assertEquals(new Integer(7), a.accumulateAndGet(6, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.accumulateAndGet(3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.get());
+        assertEquals((Integer) 7, a.accumulateAndGet(6, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.accumulateAndGet(3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.get());
     }
 
     /**
@@ -320,9 +318,9 @@
     public void testReferenceArrayGetAndUpdate() {
         AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
         a.set(0, one);
-        assertEquals(new Integer(1), a.getAndUpdate(0, Atomic8Test::addInteger17));
-        assertEquals(new Integer(18), a.getAndUpdate(0, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get(0));
+        assertEquals((Integer) 1, a.getAndUpdate(0, Atomic8Test::addInteger17));
+        assertEquals((Integer) 18, a.getAndUpdate(0, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get(0));
     }
 
     /**
@@ -332,8 +330,8 @@
     public void testReferenceArrayUpdateAndGet() {
         AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
         a.set(0, one);
-        assertEquals(new Integer(18), a.updateAndGet(0, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.updateAndGet(0, Atomic8Test::addInteger17));
+        assertEquals((Integer) 18, a.updateAndGet(0, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.updateAndGet(0, Atomic8Test::addInteger17));
     }
 
     /**
@@ -343,9 +341,9 @@
     public void testReferenceArrayGetAndAccumulate() {
         AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
         a.set(0, one);
-        assertEquals(new Integer(1), a.getAndAccumulate(0, 2, Atomic8Test::sumInteger));
-        assertEquals(new Integer(3), a.getAndAccumulate(0, 3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(6), a.get(0));
+        assertEquals((Integer) 1, a.getAndAccumulate(0, 2, Atomic8Test::sumInteger));
+        assertEquals((Integer) 3, a.getAndAccumulate(0, 3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 6, a.get(0));
     }
 
     /**
@@ -355,8 +353,8 @@
     public void testReferenceArrayAccumulateAndGet() {
         AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
         a.set(0, one);
-        assertEquals(new Integer(7), a.accumulateAndGet(0, 6, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.accumulateAndGet(0, 3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 7, a.accumulateAndGet(0, 6, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.accumulateAndGet(0, 3, Atomic8Test::sumInteger));
     }
 
     /**
@@ -470,10 +468,10 @@
     public void testReferenceFieldUpdaterGetAndUpdate() {
         AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
         a.set(this, one);
-        assertEquals(new Integer(1), a.getAndUpdate(this, Atomic8Test::addInteger17));
-        assertEquals(new Integer(18), a.getAndUpdate(this, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get(this));
-        assertEquals(new Integer(35), anIntegerField);
+        assertEquals((Integer) 1, a.getAndUpdate(this, Atomic8Test::addInteger17));
+        assertEquals((Integer) 18, a.getAndUpdate(this, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get(this));
+        assertEquals((Integer) 35, anIntegerField);
     }
 
     /**
@@ -483,10 +481,10 @@
     public void testReferenceFieldUpdaterUpdateAndGet() {
         AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
         a.set(this, one);
-        assertEquals(new Integer(18), a.updateAndGet(this, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.updateAndGet(this, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get(this));
-        assertEquals(new Integer(35), anIntegerField);
+        assertEquals((Integer) 18, a.updateAndGet(this, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.updateAndGet(this, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get(this));
+        assertEquals((Integer) 35, anIntegerField);
     }
 
     /**
@@ -496,10 +494,10 @@
     public void testReferenceFieldUpdaterGetAndAccumulate() {
         AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
         a.set(this, one);
-        assertEquals(new Integer(1), a.getAndAccumulate(this, 2, Atomic8Test::sumInteger));
-        assertEquals(new Integer(3), a.getAndAccumulate(this, 3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(6), a.get(this));
-        assertEquals(new Integer(6), anIntegerField);
+        assertEquals((Integer) 1, a.getAndAccumulate(this, 2, Atomic8Test::sumInteger));
+        assertEquals((Integer) 3, a.getAndAccumulate(this, 3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 6, a.get(this));
+        assertEquals((Integer) 6, anIntegerField);
     }
 
     /**
@@ -509,10 +507,10 @@
     public void testReferenceFieldUpdaterAccumulateAndGet() {
         AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
         a.set(this, one);
-        assertEquals(new Integer(7), a.accumulateAndGet(this, 6, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.accumulateAndGet(this, 3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.get(this));
-        assertEquals(new Integer(10), anIntegerField);
+        assertEquals((Integer) 7, a.accumulateAndGet(this, 6, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.accumulateAndGet(this, 3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.get(this));
+        assertEquals((Integer) 10, anIntegerField);
     }
 
     /**
@@ -530,9 +528,6 @@
             () -> aLongFieldUpdater().getAndUpdate(this, null),
             () -> anIntFieldUpdater().getAndUpdate(this, null),
             () -> anIntegerFieldUpdater().getAndUpdate(this, null),
-            ////() -> aLongFieldUpdater().getAndUpdate(null, Atomic8Test::addLong17),
-            ////() -> anIntFieldUpdater().getAndUpdate(null, Atomic8Test::addInt17),
-            ////() -> anIntegerFieldUpdater().getAndUpdate(null, Atomic8Test::addInteger17),
         };
         assertThrows(NullPointerException.class, throwingActions);
     }
@@ -593,4 +588,40 @@
         assertThrows(NullPointerException.class, throwingActions);
     }
 
+    /**
+     * Object arguments for parameters of type T that are not
+     * instances of the class passed to the newUpdater call will
+     * result in a ClassCastException being thrown.
+     */
+    public void testFieldUpdaters_ClassCastException() {
+        // Use raw types to allow passing wrong object type, provoking CCE
+        final AtomicLongFieldUpdater longUpdater = aLongFieldUpdater();
+        final AtomicIntegerFieldUpdater intUpdater = anIntFieldUpdater();
+        final AtomicReferenceFieldUpdater refUpdater = anIntegerFieldUpdater();
+        final Object obj = new Object();
+        for (Object x : new Object[]{ new Object(), null }) {
+            Runnable[] throwingActions = {
+                () -> longUpdater.get(x),
+                () -> intUpdater.get(x),
+                () -> refUpdater.get(x),
+
+                () -> longUpdater.set(x, 17L),
+                () -> intUpdater.set(x, 17),
+                () -> refUpdater.set(x, (Integer) 17),
+
+                () -> longUpdater.addAndGet(x, 17L),
+                () -> intUpdater.addAndGet(x, 17),
+
+                () -> longUpdater.getAndUpdate(x, y -> y),
+                () -> intUpdater.getAndUpdate(x, y -> y),
+                () -> refUpdater.getAndUpdate(x, y -> y),
+
+                () -> longUpdater.compareAndSet(x, 17L, 42L),
+                () -> intUpdater.compareAndSet(x, 17, 42),
+                () -> refUpdater.compareAndSet(x, (Integer) 17, (Integer) 42),
+            };
+            assertThrows(ClassCastException.class, throwingActions);
+        }
+    }
+
 }
--- a/jdk/test/java/util/concurrent/tck/Collection8Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/Collection8Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,18 +32,35 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 import junit.framework.Test;
 
@@ -66,16 +83,422 @@
                                       impl);
     }
 
+    Object bomb() {
+        return new Object() {
+                public boolean equals(Object x) { throw new AssertionError(); }
+                public int hashCode() { throw new AssertionError(); }
+            };
+    }
+
+    /** Checks properties of empty collections. */
+    public void testEmptyMeansEmpty() throws Throwable {
+        Collection c = impl.emptyCollection();
+        emptyMeansEmpty(c);
+
+        if (c instanceof java.io.Serializable) {
+            try {
+                emptyMeansEmpty(serialClonePossiblyFailing(c));
+            } catch (java.io.NotSerializableException ex) {
+                // excusable when we have a serializable wrapper around
+                // a non-serializable collection, as can happen with:
+                // Vector.subList() => wrapped AbstractList$RandomAccessSubList
+                if (testImplementationDetails
+                    && (! c.getClass().getName().matches(
+                                "java.util.Collections.*")))
+                    throw ex;
+            }
+        }
+
+        Collection clone = cloneableClone(c);
+        if (clone != null)
+            emptyMeansEmpty(clone);
+    }
+
+    void emptyMeansEmpty(Collection c) throws InterruptedException {
+        assertTrue(c.isEmpty());
+        assertEquals(0, c.size());
+        assertEquals("[]", c.toString());
+        {
+            Object[] a = c.toArray();
+            assertEquals(0, a.length);
+            assertSame(Object[].class, a.getClass());
+        }
+        {
+            Object[] a = new Object[0];
+            assertSame(a, c.toArray(a));
+        }
+        {
+            Integer[] a = new Integer[0];
+            assertSame(a, c.toArray(a));
+        }
+        {
+            Integer[] a = { 1, 2, 3};
+            assertSame(a, c.toArray(a));
+            assertNull(a[0]);
+            assertSame(2, a[1]);
+            assertSame(3, a[2]);
+        }
+        assertIteratorExhausted(c.iterator());
+        Consumer alwaysThrows = e -> { throw new AssertionError(); };
+        c.forEach(alwaysThrows);
+        c.iterator().forEachRemaining(alwaysThrows);
+        c.spliterator().forEachRemaining(alwaysThrows);
+        assertFalse(c.spliterator().tryAdvance(alwaysThrows));
+        if (c.spliterator().hasCharacteristics(Spliterator.SIZED))
+            assertEquals(0, c.spliterator().estimateSize());
+        assertFalse(c.contains(bomb()));
+        assertFalse(c.remove(bomb()));
+        if (c instanceof Queue) {
+            Queue q = (Queue) c;
+            assertNull(q.peek());
+            assertNull(q.poll());
+        }
+        if (c instanceof Deque) {
+            Deque d = (Deque) c;
+            assertNull(d.peekFirst());
+            assertNull(d.peekLast());
+            assertNull(d.pollFirst());
+            assertNull(d.pollLast());
+            assertIteratorExhausted(d.descendingIterator());
+            d.descendingIterator().forEachRemaining(alwaysThrows);
+            assertFalse(d.removeFirstOccurrence(bomb()));
+            assertFalse(d.removeLastOccurrence(bomb()));
+        }
+        if (c instanceof BlockingQueue) {
+            BlockingQueue q = (BlockingQueue) c;
+            assertNull(q.poll(0L, MILLISECONDS));
+        }
+        if (c instanceof BlockingDeque) {
+            BlockingDeque q = (BlockingDeque) c;
+            assertNull(q.pollFirst(0L, MILLISECONDS));
+            assertNull(q.pollLast(0L, MILLISECONDS));
+        }
+    }
+
+    public void testNullPointerExceptions() throws InterruptedException {
+        Collection c = impl.emptyCollection();
+        assertThrows(
+            NullPointerException.class,
+            () -> c.addAll(null),
+            () -> c.containsAll(null),
+            () -> c.retainAll(null),
+            () -> c.removeAll(null),
+            () -> c.removeIf(null),
+            () -> c.forEach(null),
+            () -> c.iterator().forEachRemaining(null),
+            () -> c.spliterator().forEachRemaining(null),
+            () -> c.spliterator().tryAdvance(null),
+            () -> c.toArray(null));
+
+        if (!impl.permitsNulls()) {
+            assertThrows(
+                NullPointerException.class,
+                () -> c.add(null));
+        }
+        if (!impl.permitsNulls() && c instanceof Queue) {
+            Queue q = (Queue) c;
+            assertThrows(
+                NullPointerException.class,
+                () -> q.offer(null));
+        }
+        if (!impl.permitsNulls() && c instanceof Deque) {
+            Deque d = (Deque) c;
+            assertThrows(
+                NullPointerException.class,
+                () -> d.addFirst(null),
+                () -> d.addLast(null),
+                () -> d.offerFirst(null),
+                () -> d.offerLast(null),
+                () -> d.push(null),
+                () -> d.descendingIterator().forEachRemaining(null));
+        }
+        if (c instanceof BlockingQueue) {
+            BlockingQueue q = (BlockingQueue) c;
+            assertThrows(
+                NullPointerException.class,
+                () -> {
+                    try { q.offer(null, 1L, HOURS); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }},
+                () -> {
+                    try { q.put(null); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }});
+        }
+        if (c instanceof BlockingDeque) {
+            BlockingDeque q = (BlockingDeque) c;
+            assertThrows(
+                NullPointerException.class,
+                () -> {
+                    try { q.offerFirst(null, 1L, HOURS); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }},
+                () -> {
+                    try { q.offerLast(null, 1L, HOURS); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }},
+                () -> {
+                    try { q.putFirst(null); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }},
+                () -> {
+                    try { q.putLast(null); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }});
+        }
+    }
+
+    public void testNoSuchElementExceptions() {
+        Collection c = impl.emptyCollection();
+        assertThrows(
+            NoSuchElementException.class,
+            () -> c.iterator().next());
+
+        if (c instanceof Queue) {
+            Queue q = (Queue) c;
+            assertThrows(
+                NoSuchElementException.class,
+                () -> q.element(),
+                () -> q.remove());
+        }
+        if (c instanceof Deque) {
+            Deque d = (Deque) c;
+            assertThrows(
+                NoSuchElementException.class,
+                () -> d.getFirst(),
+                () -> d.getLast(),
+                () -> d.removeFirst(),
+                () -> d.removeLast(),
+                () -> d.pop(),
+                () -> d.descendingIterator().next());
+        }
+    }
+
+    public void testRemoveIf() {
+        Collection c = impl.emptyCollection();
+        boolean ordered =
+            c.spliterator().hasCharacteristics(Spliterator.ORDERED);
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int n = rnd.nextInt(6);
+        for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
+        AtomicReference threwAt = new AtomicReference(null);
+        List orig = rnd.nextBoolean()
+            ? new ArrayList(c)
+            : Arrays.asList(c.toArray());
+
+        // Merely creating an iterator can change ArrayBlockingQueue behavior
+        Iterator it = rnd.nextBoolean() ? c.iterator() : null;
+
+        ArrayList survivors = new ArrayList();
+        ArrayList accepts = new ArrayList();
+        ArrayList rejects = new ArrayList();
+
+        Predicate randomPredicate = e -> {
+            assertNull(threwAt.get());
+            switch (rnd.nextInt(3)) {
+            case 0: accepts.add(e); return true;
+            case 1: rejects.add(e); return false;
+            case 2: threwAt.set(e); throw new ArithmeticException();
+            default: throw new AssertionError();
+            }
+        };
+        try {
+            try {
+                boolean modified = c.removeIf(randomPredicate);
+                assertNull(threwAt.get());
+                assertEquals(modified, accepts.size() > 0);
+                assertEquals(modified, rejects.size() != n);
+                assertEquals(accepts.size() + rejects.size(), n);
+                if (ordered) {
+                    assertEquals(rejects,
+                                 Arrays.asList(c.toArray()));
+                } else {
+                    assertEquals(new HashSet(rejects),
+                                 new HashSet(Arrays.asList(c.toArray())));
+                }
+            } catch (ArithmeticException ok) {
+                assertNotNull(threwAt.get());
+                assertTrue(c.contains(threwAt.get()));
+            }
+            if (it != null && impl.isConcurrent())
+                // check for weakly consistent iterator
+                while (it.hasNext()) assertTrue(orig.contains(it.next()));
+            switch (rnd.nextInt(4)) {
+            case 0: survivors.addAll(c); break;
+            case 1: survivors.addAll(Arrays.asList(c.toArray())); break;
+            case 2: c.forEach(survivors::add); break;
+            case 3: for (Object e : c) survivors.add(e); break;
+            }
+            assertTrue(orig.containsAll(accepts));
+            assertTrue(orig.containsAll(rejects));
+            assertTrue(orig.containsAll(survivors));
+            assertTrue(orig.containsAll(c));
+            assertTrue(c.containsAll(rejects));
+            assertTrue(c.containsAll(survivors));
+            assertTrue(survivors.containsAll(rejects));
+            if (threwAt.get() == null) {
+                assertEquals(n - accepts.size(), c.size());
+                for (Object x : accepts) assertFalse(c.contains(x));
+            } else {
+                // Two acceptable behaviors: entire removeIf call is one
+                // transaction, or each element processed is one transaction.
+                assertTrue(n == c.size() || n == c.size() + accepts.size());
+                int k = 0;
+                for (Object x : accepts) if (c.contains(x)) k++;
+                assertTrue(k == accepts.size() || k == 0);
+            }
+        } catch (Throwable ex) {
+            System.err.println(impl.klazz());
+            // c is at risk of corruption if we got here, so be lenient
+            try { System.err.printf("c=%s%n", c); }
+            catch (Throwable t) { t.printStackTrace(); }
+            System.err.printf("n=%d%n", n);
+            System.err.printf("orig=%s%n", orig);
+            System.err.printf("accepts=%s%n", accepts);
+            System.err.printf("rejects=%s%n", rejects);
+            System.err.printf("survivors=%s%n", survivors);
+            System.err.printf("threwAt=%s%n", threwAt.get());
+            throw ex;
+        }
+    }
+
+    /**
+     * Various ways of traversing a collection yield same elements
+     */
+    public void testIteratorEquivalence() {
+        Collection c = impl.emptyCollection();
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int n = rnd.nextInt(6);
+        for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
+        ArrayList iterated = new ArrayList();
+        ArrayList iteratedForEachRemaining = new ArrayList();
+        ArrayList tryAdvanced = new ArrayList();
+        ArrayList spliterated = new ArrayList();
+        ArrayList splitonced = new ArrayList();
+        ArrayList forEached = new ArrayList();
+        ArrayList streamForEached = new ArrayList();
+        ConcurrentLinkedQueue parallelStreamForEached = new ConcurrentLinkedQueue();
+        ArrayList removeIfed = new ArrayList();
+        for (Object x : c) iterated.add(x);
+        c.iterator().forEachRemaining(iteratedForEachRemaining::add);
+        for (Spliterator s = c.spliterator();
+             s.tryAdvance(tryAdvanced::add); ) {}
+        c.spliterator().forEachRemaining(spliterated::add);
+        {                       // trySplit returns "strict prefix"
+            Spliterator s1 = c.spliterator(), s2 = s1.trySplit();
+            if (s2 != null) s2.forEachRemaining(splitonced::add);
+            s1.forEachRemaining(splitonced::add);
+        }
+        c.forEach(forEached::add);
+        c.stream().forEach(streamForEached::add);
+        c.parallelStream().forEach(parallelStreamForEached::add);
+        c.removeIf(e -> { removeIfed.add(e); return false; });
+        boolean ordered =
+            c.spliterator().hasCharacteristics(Spliterator.ORDERED);
+        if (c instanceof List || c instanceof Deque)
+            assertTrue(ordered);
+        HashSet cset = new HashSet(c);
+        assertEquals(cset, new HashSet(parallelStreamForEached));
+        if (ordered) {
+            assertEquals(iterated, iteratedForEachRemaining);
+            assertEquals(iterated, tryAdvanced);
+            assertEquals(iterated, spliterated);
+            assertEquals(iterated, splitonced);
+            assertEquals(iterated, forEached);
+            assertEquals(iterated, streamForEached);
+            assertEquals(iterated, removeIfed);
+        } else {
+            assertEquals(cset, new HashSet(iterated));
+            assertEquals(cset, new HashSet(iteratedForEachRemaining));
+            assertEquals(cset, new HashSet(tryAdvanced));
+            assertEquals(cset, new HashSet(spliterated));
+            assertEquals(cset, new HashSet(splitonced));
+            assertEquals(cset, new HashSet(forEached));
+            assertEquals(cset, new HashSet(streamForEached));
+            assertEquals(cset, new HashSet(removeIfed));
+        }
+        if (c instanceof Deque) {
+            Deque d = (Deque) c;
+            ArrayList descending = new ArrayList();
+            ArrayList descendingForEachRemaining = new ArrayList();
+            for (Iterator it = d.descendingIterator(); it.hasNext(); )
+                descending.add(it.next());
+            d.descendingIterator().forEachRemaining(
+                e -> descendingForEachRemaining.add(e));
+            Collections.reverse(descending);
+            Collections.reverse(descendingForEachRemaining);
+            assertEquals(iterated, descending);
+            assertEquals(iterated, descendingForEachRemaining);
+        }
+    }
+
+    /**
+     * Calling Iterator#remove() after Iterator#forEachRemaining
+     * should (maybe) remove last element
+     */
+    public void testRemoveAfterForEachRemaining() {
+        Collection c = impl.emptyCollection();
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        testCollection: {
+            int n = 3 + rnd.nextInt(2);
+            for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
+            Iterator it = c.iterator();
+            assertTrue(it.hasNext());
+            assertEquals(impl.makeElement(0), it.next());
+            assertTrue(it.hasNext());
+            assertEquals(impl.makeElement(1), it.next());
+            it.forEachRemaining(e -> assertTrue(c.contains(e)));
+            if (testImplementationDetails) {
+                if (c instanceof java.util.concurrent.ArrayBlockingQueue) {
+                    assertIteratorExhausted(it);
+                } else {
+                    try { it.remove(); }
+                    catch (UnsupportedOperationException ok) {
+                        break testCollection;
+                    }
+                    assertEquals(n - 1, c.size());
+                    for (int i = 0; i < n - 1; i++)
+                        assertTrue(c.contains(impl.makeElement(i)));
+                    assertFalse(c.contains(impl.makeElement(n - 1)));
+                }
+            }
+        }
+        if (c instanceof Deque) {
+            Deque d = (Deque) impl.emptyCollection();
+            int n = 3 + rnd.nextInt(2);
+            for (int i = 0; i < n; i++) d.add(impl.makeElement(i));
+            Iterator it = d.descendingIterator();
+            assertTrue(it.hasNext());
+            assertEquals(impl.makeElement(n - 1), it.next());
+            assertTrue(it.hasNext());
+            assertEquals(impl.makeElement(n - 2), it.next());
+            it.forEachRemaining(e -> assertTrue(c.contains(e)));
+            if (testImplementationDetails) {
+                it.remove();
+                assertEquals(n - 1, d.size());
+                for (int i = 1; i < n; i++)
+                    assertTrue(d.contains(impl.makeElement(i)));
+                assertFalse(d.contains(impl.makeElement(0)));
+            }
+        }
+    }
+
     /**
      * stream().forEach returns elements in the collection
      */
-    public void testForEach() throws Throwable {
+    public void testStreamForEach() throws Throwable {
         final Collection c = impl.emptyCollection();
         final AtomicLong count = new AtomicLong(0L);
         final Object x = impl.makeElement(1);
         final Object y = impl.makeElement(2);
         final ArrayList found = new ArrayList();
-        Consumer<Object> spy = (o) -> { found.add(o); };
+        Consumer<Object> spy = o -> found.add(o);
         c.stream().forEach(spy);
         assertTrue(found.isEmpty());
 
@@ -96,7 +519,7 @@
         assertTrue(found.isEmpty());
     }
 
-    public void testForEachConcurrentStressTest() throws Throwable {
+    public void testStreamForEachConcurrentStressTest() throws Throwable {
         if (!impl.isConcurrent()) return;
         final Collection c = impl.emptyCollection();
         final long testDurationMillis = timeoutMillis();
@@ -109,7 +532,7 @@
             Runnable checkElt = () -> {
                 threadsStarted.countDown();
                 while (!done.get())
-                    c.stream().forEach((x) -> { assertSame(x, elt); }); };
+                    c.stream().forEach(x -> assertSame(x, elt)); };
             Runnable addRemove = () -> {
                 threadsStarted.countDown();
                 while (!done.get()) {
@@ -124,5 +547,144 @@
         assertNull(f2.get(0L, MILLISECONDS));
     }
 
-    // public void testCollection8DebugFail() { fail(); }
+    /**
+     * collection.forEach returns elements in the collection
+     */
+    public void testForEach() throws Throwable {
+        final Collection c = impl.emptyCollection();
+        final AtomicLong count = new AtomicLong(0L);
+        final Object x = impl.makeElement(1);
+        final Object y = impl.makeElement(2);
+        final ArrayList found = new ArrayList();
+        Consumer<Object> spy = o -> found.add(o);
+        c.forEach(spy);
+        assertTrue(found.isEmpty());
+
+        assertTrue(c.add(x));
+        c.forEach(spy);
+        assertEquals(Collections.singletonList(x), found);
+        found.clear();
+
+        assertTrue(c.add(y));
+        c.forEach(spy);
+        assertEquals(2, found.size());
+        assertTrue(found.contains(x));
+        assertTrue(found.contains(y));
+        found.clear();
+
+        c.clear();
+        c.forEach(spy);
+        assertTrue(found.isEmpty());
+    }
+
+    /**
+     * Motley crew of threads concurrently randomly hammer the collection.
+     */
+    public void testDetectRaces() throws Throwable {
+        if (!impl.isConcurrent()) return;
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        final Collection c = impl.emptyCollection();
+        final long testDurationMillis
+            = expensiveTests ? LONG_DELAY_MS : timeoutMillis();
+        final AtomicBoolean done = new AtomicBoolean(false);
+        final Object one = impl.makeElement(1);
+        final Object two = impl.makeElement(2);
+        final Consumer checkSanity = x -> assertTrue(x == one || x == two);
+        final Consumer<Object[]> checkArraySanity = array -> {
+            // assertTrue(array.length <= 2); // duplicates are permitted
+            for (Object x : array) assertTrue(x == one || x == two);
+        };
+        final Object[] emptyArray =
+            (Object[]) java.lang.reflect.Array.newInstance(one.getClass(), 0);
+        final List<Future<?>> futures;
+        final Phaser threadsStarted = new Phaser(1); // register this thread
+        final Runnable[] frobbers = {
+            () -> c.forEach(checkSanity),
+            () -> c.stream().forEach(checkSanity),
+            () -> c.parallelStream().forEach(checkSanity),
+            () -> c.spliterator().trySplit(),
+            () -> {
+                Spliterator s = c.spliterator();
+                s.tryAdvance(checkSanity);
+                s.trySplit();
+            },
+            () -> {
+                Spliterator s = c.spliterator();
+                do {} while (s.tryAdvance(checkSanity));
+            },
+            () -> { for (Object x : c) checkSanity.accept(x); },
+            () -> checkArraySanity.accept(c.toArray()),
+            () -> checkArraySanity.accept(c.toArray(emptyArray)),
+            () -> {
+                assertTrue(c.add(one));
+                assertTrue(c.contains(one));
+                assertTrue(c.remove(one));
+                assertFalse(c.contains(one));
+            },
+            () -> {
+                assertTrue(c.add(two));
+                assertTrue(c.contains(two));
+                assertTrue(c.remove(two));
+                assertFalse(c.contains(two));
+            },
+        };
+        final List<Runnable> tasks =
+            Arrays.stream(frobbers)
+            .filter(task -> rnd.nextBoolean()) // random subset
+            .map(task -> (Runnable) () -> {
+                     threadsStarted.arriveAndAwaitAdvance();
+                     while (!done.get())
+                         task.run();
+                 })
+            .collect(Collectors.toList());
+        final ExecutorService pool = Executors.newCachedThreadPool();
+        try (PoolCleaner cleaner = cleaner(pool, done)) {
+            threadsStarted.bulkRegister(tasks.size());
+            futures = tasks.stream()
+                .map(pool::submit)
+                .collect(Collectors.toList());
+            threadsStarted.arriveAndDeregister();
+            Thread.sleep(testDurationMillis);
+        }
+        for (Future future : futures)
+            assertNull(future.get(0L, MILLISECONDS));
+    }
+
+    /**
+     * Spliterators are either IMMUTABLE or truly late-binding or, if
+     * concurrent, use the same "late-binding style" of returning
+     * elements added between creation and first use.
+     */
+    public void testLateBindingStyle() {
+        if (!testImplementationDetails) return;
+        if (impl.klazz() == ArrayList.class) return; // for jdk8
+        // Immutable (snapshot) spliterators are exempt
+        if (impl.emptyCollection().spliterator()
+            .hasCharacteristics(Spliterator.IMMUTABLE))
+            return;
+        final Object one = impl.makeElement(1);
+        {
+            final Collection c = impl.emptyCollection();
+            final Spliterator split = c.spliterator();
+            c.add(one);
+            assertTrue(split.tryAdvance(e -> { assertSame(e, one); }));
+            assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
+            assertTrue(c.contains(one));
+        }
+        {
+            final AtomicLong count = new AtomicLong(0);
+            final Collection c = impl.emptyCollection();
+            final Spliterator split = c.spliterator();
+            c.add(one);
+            split.forEachRemaining(
+                e -> { assertSame(e, one); count.getAndIncrement(); });
+            assertEquals(1L, count.get());
+            assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
+            assertTrue(c.contains(one));
+        }
+    }
+
+//     public void testCollection8DebugFail() {
+//         fail(impl.klazz().getSimpleName());
+//     }
 }
--- a/jdk/test/java/util/concurrent/tck/CollectionTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/CollectionTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,8 +32,6 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-import java.util.Collection;
-
 import junit.framework.Test;
 
 /**
@@ -58,11 +56,7 @@
                                         impl));
     }
 
-    /** A test of the CollectionImplementation implementation ! */
-    public void testEmptyMeansEmpty() {
-        assertTrue(impl.emptyCollection().isEmpty());
-        assertEquals(0, impl.emptyCollection().size());
-    }
-
-    // public void testCollectionDebugFail() { fail(); }
+//     public void testCollectionDebugFail() {
+//         fail(impl.klazz().getSimpleName());
+//     }
 }
--- a/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -174,26 +174,26 @@
 
     void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
         checkCompletedExceptionally(f, true,
-            (t) -> assertTrue(t instanceof CFException));
+            t -> assertTrue(t instanceof CFException));
     }
 
     void checkCompletedWithWrappedCancellationException(CompletableFuture<?> f) {
         checkCompletedExceptionally(f, true,
-            (t) -> assertTrue(t instanceof CancellationException));
+            t -> assertTrue(t instanceof CancellationException));
     }
 
     void checkCompletedWithTimeoutException(CompletableFuture<?> f) {
         checkCompletedExceptionally(f, false,
-            (t) -> assertTrue(t instanceof TimeoutException));
+            t -> assertTrue(t instanceof TimeoutException));
     }
 
     void checkCompletedWithWrappedException(CompletableFuture<?> f,
                                             Throwable ex) {
-        checkCompletedExceptionally(f, true, (t) -> assertSame(t, ex));
+        checkCompletedExceptionally(f, true, t -> assertSame(t, ex));
     }
 
     void checkCompletedExceptionally(CompletableFuture<?> f, Throwable ex) {
-        checkCompletedExceptionally(f, false, (t) -> assertSame(t, ex));
+        checkCompletedExceptionally(f, false, t -> assertSame(t, ex));
     }
 
     void checkCancelled(CompletableFuture<?> f) {
@@ -3284,12 +3284,12 @@
 
             () -> f.thenApply(null),
             () -> f.thenApplyAsync(null),
-            () -> f.thenApplyAsync((x) -> x, null),
+            () -> f.thenApplyAsync(x -> x, null),
             () -> f.thenApplyAsync(null, exec),
 
             () -> f.thenAccept(null),
             () -> f.thenAcceptAsync(null),
-            () -> f.thenAcceptAsync((x) -> {} , null),
+            () -> f.thenAcceptAsync(x -> {} , null),
             () -> f.thenAcceptAsync(null, exec),
 
             () -> f.thenRun(null),
@@ -3324,18 +3324,18 @@
             () -> f.applyToEither(g, null),
             () -> f.applyToEitherAsync(g, null),
             () -> f.applyToEitherAsync(g, null, exec),
-            () -> f.applyToEither(nullFuture, (x) -> x),
-            () -> f.applyToEitherAsync(nullFuture, (x) -> x),
-            () -> f.applyToEitherAsync(nullFuture, (x) -> x, exec),
-            () -> f.applyToEitherAsync(g, (x) -> x, null),
+            () -> f.applyToEither(nullFuture, x -> x),
+            () -> f.applyToEitherAsync(nullFuture, x -> x),
+            () -> f.applyToEitherAsync(nullFuture, x -> x, exec),
+            () -> f.applyToEitherAsync(g, x -> x, null),
 
             () -> f.acceptEither(g, null),
             () -> f.acceptEitherAsync(g, null),
             () -> f.acceptEitherAsync(g, null, exec),
-            () -> f.acceptEither(nullFuture, (x) -> {}),
-            () -> f.acceptEitherAsync(nullFuture, (x) -> {}),
-            () -> f.acceptEitherAsync(nullFuture, (x) -> {}, exec),
-            () -> f.acceptEitherAsync(g, (x) -> {}, null),
+            () -> f.acceptEither(nullFuture, x -> {}),
+            () -> f.acceptEitherAsync(nullFuture, x -> {}),
+            () -> f.acceptEitherAsync(nullFuture, x -> {}, exec),
+            () -> f.acceptEitherAsync(g, x -> {}, null),
 
             () -> f.runAfterEither(g, null),
             () -> f.runAfterEitherAsync(g, null),
@@ -3401,18 +3401,18 @@
         for (CompletableFuture<Integer> src : srcs) {
             List<CompletableFuture<?>> fs = new ArrayList<>();
             fs.add(src.thenRunAsync(() -> {}, e));
-            fs.add(src.thenAcceptAsync((z) -> {}, e));
-            fs.add(src.thenApplyAsync((z) -> z, e));
+            fs.add(src.thenAcceptAsync(z -> {}, e));
+            fs.add(src.thenApplyAsync(z -> z, e));
 
             fs.add(src.thenCombineAsync(src, (x, y) -> x, e));
             fs.add(src.thenAcceptBothAsync(src, (x, y) -> {}, e));
             fs.add(src.runAfterBothAsync(src, () -> {}, e));
 
-            fs.add(src.applyToEitherAsync(src, (z) -> z, e));
-            fs.add(src.acceptEitherAsync(src, (z) -> {}, e));
+            fs.add(src.applyToEitherAsync(src, z -> z, e));
+            fs.add(src.acceptEitherAsync(src, z -> {}, e));
             fs.add(src.runAfterEitherAsync(src, () -> {}, e));
 
-            fs.add(src.thenComposeAsync((z) -> null, e));
+            fs.add(src.thenComposeAsync(z -> null, e));
             fs.add(src.whenCompleteAsync((z, t) -> {}, e));
             fs.add(src.handleAsync((z, t) -> null, e));
 
@@ -3445,11 +3445,11 @@
         {
             List<CompletableFuture<?>> fs = new ArrayList<>();
 
-            fs.add(complete.applyToEitherAsync(incomplete, (z) -> z, e));
-            fs.add(incomplete.applyToEitherAsync(complete, (z) -> z, e));
-
-            fs.add(complete.acceptEitherAsync(incomplete, (z) -> {}, e));
-            fs.add(incomplete.acceptEitherAsync(complete, (z) -> {}, e));
+            fs.add(complete.applyToEitherAsync(incomplete, z -> z, e));
+            fs.add(incomplete.applyToEitherAsync(complete, z -> z, e));
+
+            fs.add(complete.acceptEitherAsync(incomplete, z -> {}, e));
+            fs.add(incomplete.acceptEitherAsync(complete, z -> {}, e));
 
             fs.add(complete.runAfterEitherAsync(incomplete, () -> {}, e));
             fs.add(incomplete.runAfterEitherAsync(complete, () -> {}, e));
@@ -3488,18 +3488,18 @@
 
         List<CompletableFuture<?>> fs = new ArrayList<>();
         fs.add(incomplete.thenRunAsync(() -> {}, e));
-        fs.add(incomplete.thenAcceptAsync((z) -> {}, e));
-        fs.add(incomplete.thenApplyAsync((z) -> z, e));
+        fs.add(incomplete.thenAcceptAsync(z -> {}, e));
+        fs.add(incomplete.thenApplyAsync(z -> z, e));
 
         fs.add(incomplete.thenCombineAsync(incomplete, (x, y) -> x, e));
         fs.add(incomplete.thenAcceptBothAsync(incomplete, (x, y) -> {}, e));
         fs.add(incomplete.runAfterBothAsync(incomplete, () -> {}, e));
 
-        fs.add(incomplete.applyToEitherAsync(incomplete, (z) -> z, e));
-        fs.add(incomplete.acceptEitherAsync(incomplete, (z) -> {}, e));
+        fs.add(incomplete.applyToEitherAsync(incomplete, z -> z, e));
+        fs.add(incomplete.acceptEitherAsync(incomplete, z -> {}, e));
         fs.add(incomplete.runAfterEitherAsync(incomplete, () -> {}, e));
 
-        fs.add(incomplete.thenComposeAsync((z) -> null, e));
+        fs.add(incomplete.thenComposeAsync(z -> null, e));
         fs.add(incomplete.whenCompleteAsync((z, t) -> {}, e));
         fs.add(incomplete.handleAsync((z, t) -> null, e));
 
@@ -3720,7 +3720,7 @@
     public void testCompleteAsync2() {
         CompletableFuture<Integer> f = new CompletableFuture<>();
         CFException ex = new CFException();
-        f.completeAsync(() -> {if (true) throw ex; return 1;});
+        f.completeAsync(() -> { throw ex; });
         try {
             f.join();
             shouldThrow();
@@ -3750,7 +3750,7 @@
         CompletableFuture<Integer> f = new CompletableFuture<>();
         CFException ex = new CFException();
         ThreadExecutor executor = new ThreadExecutor();
-        f.completeAsync(() -> {if (true) throw ex; return 1;}, executor);
+        f.completeAsync(() -> { throw ex; }, executor);
         try {
             f.join();
             shouldThrow();
@@ -3909,31 +3909,31 @@
         List<Function<CompletableFuture<Integer>, CompletableFuture<?>>> funs
             = new ArrayList<>();
 
-        funs.add((y) -> m.thenRun(y, noopRunnable));
-        funs.add((y) -> m.thenAccept(y, noopConsumer));
-        funs.add((y) -> m.thenApply(y, incFunction));
-
-        funs.add((y) -> m.runAfterEither(y, incomplete, noopRunnable));
-        funs.add((y) -> m.acceptEither(y, incomplete, noopConsumer));
-        funs.add((y) -> m.applyToEither(y, incomplete, incFunction));
-
-        funs.add((y) -> m.runAfterBoth(y, v42, noopRunnable));
-        funs.add((y) -> m.runAfterBoth(v42, y, noopRunnable));
-        funs.add((y) -> m.thenAcceptBoth(y, v42, new SubtractAction(m)));
-        funs.add((y) -> m.thenAcceptBoth(v42, y, new SubtractAction(m)));
-        funs.add((y) -> m.thenCombine(y, v42, new SubtractFunction(m)));
-        funs.add((y) -> m.thenCombine(v42, y, new SubtractFunction(m)));
-
-        funs.add((y) -> m.whenComplete(y, (Integer r, Throwable t) -> {}));
-
-        funs.add((y) -> m.thenCompose(y, new CompletableFutureInc(m)));
-
-        funs.add((y) -> CompletableFuture.allOf(y));
-        funs.add((y) -> CompletableFuture.allOf(y, v42));
-        funs.add((y) -> CompletableFuture.allOf(v42, y));
-        funs.add((y) -> CompletableFuture.anyOf(y));
-        funs.add((y) -> CompletableFuture.anyOf(y, incomplete));
-        funs.add((y) -> CompletableFuture.anyOf(incomplete, y));
+        funs.add(y -> m.thenRun(y, noopRunnable));
+        funs.add(y -> m.thenAccept(y, noopConsumer));
+        funs.add(y -> m.thenApply(y, incFunction));
+
+        funs.add(y -> m.runAfterEither(y, incomplete, noopRunnable));
+        funs.add(y -> m.acceptEither(y, incomplete, noopConsumer));
+        funs.add(y -> m.applyToEither(y, incomplete, incFunction));
+
+        funs.add(y -> m.runAfterBoth(y, v42, noopRunnable));
+        funs.add(y -> m.runAfterBoth(v42, y, noopRunnable));
+        funs.add(y -> m.thenAcceptBoth(y, v42, new SubtractAction(m)));
+        funs.add(y -> m.thenAcceptBoth(v42, y, new SubtractAction(m)));
+        funs.add(y -> m.thenCombine(y, v42, new SubtractFunction(m)));
+        funs.add(y -> m.thenCombine(v42, y, new SubtractFunction(m)));
+
+        funs.add(y -> m.whenComplete(y, (Integer r, Throwable t) -> {}));
+
+        funs.add(y -> m.thenCompose(y, new CompletableFutureInc(m)));
+
+        funs.add(y -> CompletableFuture.allOf(y));
+        funs.add(y -> CompletableFuture.allOf(y, v42));
+        funs.add(y -> CompletableFuture.allOf(v42, y));
+        funs.add(y -> CompletableFuture.anyOf(y));
+        funs.add(y -> CompletableFuture.anyOf(y, incomplete));
+        funs.add(y -> CompletableFuture.anyOf(incomplete, y));
 
         for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
                  fun : funs) {
@@ -3990,12 +3990,12 @@
     public void testMinimalCompletionStage_minimality() {
         if (!testImplementationDetails) return;
         Function<Method, String> toSignature =
-            (method) -> method.getName() + Arrays.toString(method.getParameterTypes());
+            method -> method.getName() + Arrays.toString(method.getParameterTypes());
         Predicate<Method> isNotStatic =
-            (method) -> (method.getModifiers() & Modifier.STATIC) == 0;
+            method -> (method.getModifiers() & Modifier.STATIC) == 0;
         List<Method> minimalMethods =
             Stream.of(Object.class, CompletionStage.class)
-            .flatMap((klazz) -> Stream.of(klazz.getMethods()))
+            .flatMap(klazz -> Stream.of(klazz.getMethods()))
             .filter(isNotStatic)
             .collect(Collectors.toList());
         // Methods from CompletableFuture permitted NOT to throw UOE
@@ -4011,7 +4011,7 @@
             .collect(Collectors.toSet());
         List<Method> allMethods = Stream.of(CompletableFuture.class.getMethods())
             .filter(isNotStatic)
-            .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method)))
+            .filter(method -> !permittedMethodSignatures.contains(toSignature.apply(method)))
             .collect(Collectors.toList());
 
         List<CompletionStage<Integer>> stages = new ArrayList<>();
@@ -4171,7 +4171,7 @@
         CompletionStage<Integer> minimal = f.minimalCompletionStage();
         CompletableFuture<Integer> g = new CompletableFuture<>();
         if (!createIncomplete) assertTrue(f.complete(v1));
-        minimal.thenAccept((x) -> g.complete(x));
+        minimal.thenAccept(x -> g.complete(x));
         if (createIncomplete) assertTrue(f.complete(v1));
         g.join();
         checkCompletedNormally(g, v1);
@@ -4195,7 +4195,7 @@
         static <T,U,V> Function<T, CompletableFuture<V>> compose
             (Function<T, CompletableFuture<U>> f,
              Function<U, CompletableFuture<V>> g) {
-            return (x) -> f.apply(x).thenCompose(g);
+            return x -> f.apply(x).thenCompose(g);
         }
 
         static void assertZero(CompletableFuture<?> f) {
@@ -4275,9 +4275,9 @@
 
         // Some mutually non-commutative functions
         Function<Long, CompletableFuture<Long>> triple
-            = (x) -> Monad.unit(3 * x);
+            = x -> Monad.unit(3 * x);
         Function<Long, CompletableFuture<Long>> inc
-            = (x) -> Monad.unit(x + 1);
+            = x -> Monad.unit(x + 1);
 
         // unit is a right identity: m >>= unit === m
         Monad.assertFutureEquals(inc.apply(5L).thenCompose(unit),
@@ -4289,7 +4289,7 @@
         // associativity: (m >>= f) >>= g === m >>= ( \x -> (f x >>= g) )
         Monad.assertFutureEquals(
             unit.apply(5L).thenCompose(inc).thenCompose(triple),
-            unit.apply(5L).thenCompose((x) -> inc.apply(x).thenCompose(triple)));
+            unit.apply(5L).thenCompose(x -> inc.apply(x).thenCompose(triple)));
 
         // The case for CompletableFuture as an additive monad is weaker...
 
@@ -4299,7 +4299,7 @@
         // left zero: zero >>= f === zero
         Monad.assertZero(zero.thenCompose(inc));
         // right zero: f >>= (\x -> zero) === zero
-        Monad.assertZero(inc.apply(5L).thenCompose((x) -> zero));
+        Monad.assertZero(inc.apply(5L).thenCompose(x -> zero));
 
         // f plus zero === f
         Monad.assertFutureEquals(Monad.unit(5L),
@@ -4357,8 +4357,8 @@
         final AtomicInteger count = new AtomicInteger(0);
         for (int i = 0; i < n; i++) {
             head.thenRun(() -> count.getAndIncrement());
-            head.thenAccept((x) -> count.getAndIncrement());
-            head.thenApply((x) -> count.getAndIncrement());
+            head.thenAccept(x -> count.getAndIncrement());
+            head.thenApply(x -> count.getAndIncrement());
 
             head.runAfterBoth(complete, () -> count.getAndIncrement());
             head.thenAcceptBoth(complete, (x, y) -> count.getAndIncrement());
@@ -4368,11 +4368,11 @@
             complete.thenCombine(head, (x, y) -> count.getAndIncrement());
 
             head.runAfterEither(new CompletableFuture<Void>(), () -> count.getAndIncrement());
-            head.acceptEither(new CompletableFuture<Void>(), (x) -> count.getAndIncrement());
-            head.applyToEither(new CompletableFuture<Void>(), (x) -> count.getAndIncrement());
+            head.acceptEither(new CompletableFuture<Void>(), x -> count.getAndIncrement());
+            head.applyToEither(new CompletableFuture<Void>(), x -> count.getAndIncrement());
             new CompletableFuture<Void>().runAfterEither(head, () -> count.getAndIncrement());
-            new CompletableFuture<Void>().acceptEither(head, (x) -> count.getAndIncrement());
-            new CompletableFuture<Void>().applyToEither(head, (x) -> count.getAndIncrement());
+            new CompletableFuture<Void>().acceptEither(head, x -> count.getAndIncrement());
+            new CompletableFuture<Void>().applyToEither(head, x -> count.getAndIncrement());
         }
         head.complete(null);
         assertEquals(5 * 3 * n, count.get());
@@ -4389,11 +4389,11 @@
             f.complete(null);
 
             f = new CompletableFuture<>();
-            f.acceptEither(incomplete, (x) -> {});
+            f.acceptEither(incomplete, x -> {});
             f.complete(null);
 
             f = new CompletableFuture<>();
-            f.applyToEither(incomplete, (x) -> x);
+            f.applyToEither(incomplete, x -> x);
             f.complete(null);
 
             f = new CompletableFuture<>();
@@ -4407,11 +4407,11 @@
             f.complete(null);
 
             f = new CompletableFuture<>();
-            incomplete.acceptEither(f, (x) -> {});
+            incomplete.acceptEither(f, x -> {});
             f.complete(null);
 
             f = new CompletableFuture<>();
-            incomplete.applyToEither(f, (x) -> x);
+            incomplete.applyToEither(f, x -> x);
             f.complete(null);
 
             f = new CompletableFuture<>();
--- a/jdk/test/java/util/concurrent/tck/ConcurrentHashMap8Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentHashMap8Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -43,6 +43,8 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.Spliterator;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.LongAdder;
 import java.util.function.BiFunction;
@@ -88,7 +90,7 @@
      */
     public void testComputeIfAbsent() {
         ConcurrentHashMap map = map5();
-        map.computeIfAbsent(six, (x) -> "Z");
+        map.computeIfAbsent(six, x -> "Z");
         assertTrue(map.containsKey(six));
     }
 
@@ -97,7 +99,7 @@
      */
     public void testComputeIfAbsent2() {
         ConcurrentHashMap map = map5();
-        assertEquals("A", map.computeIfAbsent(one, (x) -> "Z"));
+        assertEquals("A", map.computeIfAbsent(one, x -> "Z"));
     }
 
     /**
@@ -105,7 +107,7 @@
      */
     public void testComputeIfAbsent3() {
         ConcurrentHashMap map = map5();
-        map.computeIfAbsent(six, (x) -> null);
+        map.computeIfAbsent(six, x -> null);
         assertFalse(map.containsKey(six));
     }
 
@@ -1114,4 +1116,30 @@
         assertNull(r);
     }
 
+    /**
+     * Tests performance of computeIfAbsent when the element is present.
+     * See JDK-8161372
+     * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testcomputeIfAbsent_performance -Djsr166.expensiveTests=true tck
+     */
+    public void testcomputeIfAbsent_performance() {
+        final int mapSize = 20;
+        final int iterations = expensiveTests ? (1 << 23) : mapSize * 2;
+        final int threads = expensiveTests ? 10 : 2;
+        final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
+        for (int i = 0; i < mapSize; i++)
+            map.put(i, i);
+        final ExecutorService pool = Executors.newFixedThreadPool(2);
+        try (PoolCleaner cleaner = cleaner(pool)) {
+            Runnable r = new CheckedRunnable() {
+                public void realRun() {
+                    int result = 0;
+                    for (int i = 0; i < iterations; i++)
+                        result += map.computeIfAbsent(i % mapSize, k -> k + k);
+                    if (result == -42) throw new Error();
+                }};
+            for (int i = 0; i < threads; i++)
+                pool.execute(r);
+        }
+    }
+
 }
--- a/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -864,30 +864,4 @@
         assertEquals(mapSize, map.size());
     }
 
-    /**
-     * Tests performance of computeIfAbsent when the element is present.
-     * See JDK-8161372
-     * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testcomputeIfAbsent_performance -Djsr166.expensiveTests=true tck
-     */
-    public void testcomputeIfAbsent_performance() {
-        final int mapSize = 20;
-        final int iterations = expensiveTests ? (1 << 23) : mapSize * 2;
-        final int threads = expensiveTests ? 10 : 2;
-        final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
-        for (int i = 0; i < mapSize; i++)
-            map.put(i, i);
-        final ExecutorService pool = Executors.newFixedThreadPool(2);
-        try (PoolCleaner cleaner = cleaner(pool)) {
-            Runnable r = new CheckedRunnable() {
-                public void realRun() {
-                    int result = 0;
-                    for (int i = 0; i < iterations; i++)
-                        result += map.computeIfAbsent(i % mapSize, (k) -> k + k);
-                    if (result == -42) throw new Error();
-                }};
-            for (int i = 0; i < threads; i++)
-                pool.execute(r);
-        }
-    }
-
 }
--- a/jdk/test/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -52,12 +52,20 @@
     }
 
     public static Test suite() {
-        return new TestSuite(ConcurrentLinkedDequeTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ConcurrentLinkedDeque.class; }
+            public Collection emptyCollection() { return new ConcurrentLinkedDeque(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
+        return newTestSuite(ConcurrentLinkedDequeTest.class,
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new deque of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private ConcurrentLinkedDeque<Integer> populatedDeque(int n) {
         ConcurrentLinkedDeque<Integer> q = new ConcurrentLinkedDeque<Integer>();
@@ -66,6 +74,8 @@
             assertTrue(q.offer(new Integer(i)));
         assertFalse(q.isEmpty());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peekFirst());
+        assertEquals((Integer) (n - 1), q.peekLast());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -50,12 +50,20 @@
     }
 
     public static Test suite() {
-        return new TestSuite(ConcurrentLinkedQueueTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ConcurrentLinkedQueue.class; }
+            public Collection emptyCollection() { return new ConcurrentLinkedQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
+        return newTestSuite(ConcurrentLinkedQueueTest.class,
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private ConcurrentLinkedQueue<Integer> populatedQueue(int n) {
         ConcurrentLinkedQueue<Integer> q = new ConcurrentLinkedQueue<Integer>();
@@ -64,6 +72,7 @@
             assertTrue(q.offer(new Integer(i)));
         assertFalse(q.isEmpty());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -62,7 +62,7 @@
 
     /**
      * Returns a new set of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private ConcurrentSkipListSet<Integer> populatedSet(int n) {
         ConcurrentSkipListSet<Integer> q =
--- a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubSetTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubSetTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -57,7 +57,7 @@
 
     /**
      * Returns a new set of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private NavigableSet<Integer> populatedSet(int n) {
         ConcurrentSkipListSet<Integer> q =
--- a/jdk/test/java/util/concurrent/tck/CopyOnWriteArrayListTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/CopyOnWriteArrayListTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -53,7 +53,22 @@
     }
 
     public static Test suite() {
-        return new TestSuite(CopyOnWriteArrayListTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ArrayList.class; }
+            public List emptyCollection() { return new CopyOnWriteArrayList(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return true; }
+        }
+        class SubListImplementation extends Implementation {
+            public List emptyCollection() {
+                return super.emptyCollection().subList(0, 0);
+            }
+        }
+        return newTestSuite(
+                CopyOnWriteArrayListTest.class,
+                CollectionTest.testSuite(new Implementation()),
+                CollectionTest.testSuite(new SubListImplementation()));
     }
 
     static CopyOnWriteArrayList<Integer> populatedArray(int n) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/CountedCompleter8Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,168 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class CountedCompleter8Test extends JSR166TestCase {
+
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        return new TestSuite(CountedCompleter8Test.class);
+    }
+
+    /** CountedCompleter class javadoc code sample, version 1. */
+    public static <E> void forEach1(E[] array, Consumer<E> action) {
+        class Task extends CountedCompleter<Void> {
+            final int lo, hi;
+            Task(Task parent, int lo, int hi) {
+                super(parent); this.lo = lo; this.hi = hi;
+            }
+
+            public void compute() {
+                if (hi - lo >= 2) {
+                    int mid = (lo + hi) >>> 1;
+                    // must set pending count before fork
+                    setPendingCount(2);
+                    new Task(this, mid, hi).fork(); // right child
+                    new Task(this, lo, mid).fork(); // left child
+                }
+                else if (hi > lo)
+                    action.accept(array[lo]);
+                tryComplete();
+            }
+        }
+        new Task(null, 0, array.length).invoke();
+    }
+
+    /** CountedCompleter class javadoc code sample, version 2. */
+    public static <E> void forEach2(E[] array, Consumer<E> action) {
+        class Task extends CountedCompleter<Void> {
+            final int lo, hi;
+            Task(Task parent, int lo, int hi) {
+                super(parent); this.lo = lo; this.hi = hi;
+            }
+
+            public void compute() {
+                if (hi - lo >= 2) {
+                    int mid = (lo + hi) >>> 1;
+                    setPendingCount(1); // looks off by one, but correct!
+                    new Task(this, mid, hi).fork(); // right child
+                    new Task(this, lo, mid).compute(); // direct invoke
+                } else {
+                    if (hi > lo)
+                        action.accept(array[lo]);
+                    tryComplete();
+                }
+            }
+        }
+        new Task(null, 0, array.length).invoke();
+    }
+
+    /** CountedCompleter class javadoc code sample, version 3. */
+    public static <E> void forEach3(E[] array, Consumer<E> action) {
+        class Task extends CountedCompleter<Void> {
+            final int lo, hi;
+            Task(Task parent, int lo, int hi) {
+                super(parent); this.lo = lo; this.hi = hi;
+            }
+
+            public void compute() {
+                int n = hi - lo;
+                for (; n >= 2; n /= 2) {
+                    addToPendingCount(1);
+                    new Task(this, lo + n/2, lo + n).fork();
+                }
+                if (n > 0)
+                    action.accept(array[lo]);
+                propagateCompletion();
+            }
+        }
+        new Task(null, 0, array.length).invoke();
+    }
+
+    /** CountedCompleter class javadoc code sample, version 4. */
+    public static <E> void forEach4(E[] array, Consumer<E> action) {
+        class Task extends CountedCompleter<Void> {
+            final int lo, hi;
+            Task(Task parent, int lo, int hi) {
+                super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
+                this.lo = lo; this.hi = hi;
+            }
+
+            public void compute() {
+                for (int n = hi - lo; n >= 2; n /= 2)
+                    new Task(this, lo + n/2, lo + n).fork();
+                action.accept(array[lo]);
+                propagateCompletion();
+            }
+        }
+        if (array.length > 0)
+            new Task(null, 0, array.length).invoke();
+    }
+
+    void testRecursiveDecomposition(
+        BiConsumer<Integer[], Consumer<Integer>> action) {
+        int n = ThreadLocalRandom.current().nextInt(8);
+        Integer[] a = new Integer[n];
+        for (int i = 0; i < n; i++) a[i] = i + 1;
+        AtomicInteger ai = new AtomicInteger(0);
+        action.accept(a, ai::addAndGet);
+        assertEquals(n * (n + 1) / 2, ai.get());
+    }
+
+    /**
+     * Variants of divide-by-two recursive decomposition into leaf tasks,
+     * as described in the CountedCompleter class javadoc code samples
+     */
+    public void testRecursiveDecomposition() {
+        testRecursiveDecomposition(CountedCompleter8Test::forEach1);
+        testRecursiveDecomposition(CountedCompleter8Test::forEach2);
+        testRecursiveDecomposition(CountedCompleter8Test::forEach3);
+        testRecursiveDecomposition(CountedCompleter8Test::forEach4);
+    }
+
+}
--- a/jdk/test/java/util/concurrent/tck/CountedCompleterTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/CountedCompleterTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -44,8 +44,6 @@
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -1872,115 +1870,4 @@
         testInvokeOnPool(singletonPool(), a);
     }
 
-    /** CountedCompleter class javadoc code sample, version 1. */
-    public static <E> void forEach1(E[] array, Consumer<E> action) {
-        class Task extends CountedCompleter<Void> {
-            final int lo, hi;
-            Task(Task parent, int lo, int hi) {
-                super(parent); this.lo = lo; this.hi = hi;
-            }
-
-            public void compute() {
-                if (hi - lo >= 2) {
-                    int mid = (lo + hi) >>> 1;
-                    // must set pending count before fork
-                    setPendingCount(2);
-                    new Task(this, mid, hi).fork(); // right child
-                    new Task(this, lo, mid).fork(); // left child
-                }
-                else if (hi > lo)
-                    action.accept(array[lo]);
-                tryComplete();
-            }
-        }
-        new Task(null, 0, array.length).invoke();
-    }
-
-    /** CountedCompleter class javadoc code sample, version 2. */
-    public static <E> void forEach2(E[] array, Consumer<E> action) {
-        class Task extends CountedCompleter<Void> {
-            final int lo, hi;
-            Task(Task parent, int lo, int hi) {
-                super(parent); this.lo = lo; this.hi = hi;
-            }
-
-            public void compute() {
-                if (hi - lo >= 2) {
-                    int mid = (lo + hi) >>> 1;
-                    setPendingCount(1); // looks off by one, but correct!
-                    new Task(this, mid, hi).fork(); // right child
-                    new Task(this, lo, mid).compute(); // direct invoke
-                } else {
-                    if (hi > lo)
-                        action.accept(array[lo]);
-                    tryComplete();
-                }
-            }
-        }
-        new Task(null, 0, array.length).invoke();
-    }
-
-    /** CountedCompleter class javadoc code sample, version 3. */
-    public static <E> void forEach3(E[] array, Consumer<E> action) {
-        class Task extends CountedCompleter<Void> {
-            final int lo, hi;
-            Task(Task parent, int lo, int hi) {
-                super(parent); this.lo = lo; this.hi = hi;
-            }
-
-            public void compute() {
-                int n = hi - lo;
-                for (; n >= 2; n /= 2) {
-                    addToPendingCount(1);
-                    new Task(this, lo + n/2, lo + n).fork();
-                }
-                if (n > 0)
-                    action.accept(array[lo]);
-                propagateCompletion();
-            }
-        }
-        new Task(null, 0, array.length).invoke();
-    }
-
-    /** CountedCompleter class javadoc code sample, version 4. */
-    public static <E> void forEach4(E[] array, Consumer<E> action) {
-        class Task extends CountedCompleter<Void> {
-            final int lo, hi;
-            Task(Task parent, int lo, int hi) {
-                super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
-                this.lo = lo; this.hi = hi;
-            }
-
-            public void compute() {
-                for (int n = hi - lo; n >= 2; n /= 2)
-                    new Task(this, lo + n/2, lo + n).fork();
-                action.accept(array[lo]);
-                propagateCompletion();
-            }
-        }
-        if (array.length > 0)
-            new Task(null, 0, array.length).invoke();
-    }
-
-    void testRecursiveDecomposition(
-        BiConsumer<Integer[], Consumer<Integer>> action) {
-        int n = ThreadLocalRandom.current().nextInt(8);
-        Integer[] a = new Integer[n];
-        for (int i = 0; i < n; i++) a[i] = i + 1;
-        AtomicInteger ai = new AtomicInteger(0);
-        action.accept(a, (x) -> ai.addAndGet(x));
-        assertEquals(n * (n + 1) / 2, ai.get());
-    }
-
-    /**
-     * Variants of divide-by-two recursive decomposition into leaf tasks,
-     * as described in the CountedCompleter class javadoc code samples
-     */
-    public void testRecursiveDecomposition() {
-        testRecursiveDecomposition(CountedCompleterTest::forEach1);
-        testRecursiveDecomposition(CountedCompleterTest::forEach2);
-        testRecursiveDecomposition(CountedCompleterTest::forEach3);
-        testRecursiveDecomposition(CountedCompleterTest::forEach4);
-    }
-
 }
--- a/jdk/test/java/util/concurrent/tck/DelayQueueTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/DelayQueueTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -66,8 +66,16 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return DelayQueue.class; }
+            public Collection emptyCollection() { return new DelayQueue(); }
+            public Object makeElement(int i) { return new PDelay(i); }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(DelayQueueTest.class,
-                            new Generic().testSuite());
+                            new Generic().testSuite(),
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
@@ -144,7 +152,7 @@
 
     /**
      * Returns a new queue of given size containing consecutive
-     * PDelays 0 ... n.
+     * PDelays 0 ... n - 1.
      */
     private DelayQueue<PDelay> populatedQueue(int n) {
         DelayQueue<PDelay> q = new DelayQueue<PDelay>();
@@ -156,6 +164,7 @@
         assertFalse(q.isEmpty());
         assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
         assertEquals(n, q.size());
+        assertEquals(new PDelay(0), q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/ExecutorCompletionService9Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ExecutorCompletionService9Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,6 +34,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 import java.util.HashSet;
@@ -77,7 +78,7 @@
         List<Future<Integer>> futures = new ArrayList<>(n);
         Integer result = null;
         try {
-            solvers.forEach((solver) -> futures.add(cs.submit(solver)));
+            solvers.forEach(solver -> futures.add(cs.submit(solver)));
             for (int i = n; i > 0; i--) {
                 try {
                     Integer r = cs.take().get();
@@ -88,17 +89,17 @@
                 } catch (ExecutionException ignore) {}
             }
         } finally {
-            futures.forEach((future) -> future.cancel(true));
+            futures.forEach(future -> future.cancel(true));
         }
 
         if (result != null)
             use(result);
     }
 
-    HashSet<Integer> results;
+    ArrayList<Integer> results;
 
     void use(Integer x) {
-        if (results == null) results = new HashSet<Integer>();
+        if (results == null) results = new ArrayList<Integer>();
         results.add(x);
     }
 
@@ -107,6 +108,7 @@
      */
     public void testSolveAll()
         throws InterruptedException, ExecutionException {
+        results = null;
         Set<Callable<Integer>> solvers = Set.of(
             () -> null,
             () -> 1,
@@ -114,7 +116,8 @@
             () -> 3,
             () -> null);
         solveAll(cachedThreadPool, solvers);
-        assertEquals(Set.of(1, 2, 3), results);
+        results.sort(Comparator.naturalOrder());
+        assertEquals(List.of(1, 2, 3), results);
     }
 
     /**
@@ -122,6 +125,7 @@
      */
     public void testSolveAny()
         throws InterruptedException {
+        results = null;
         Set<Callable<Integer>> solvers = Set.of(
             () -> { throw new ArithmeticException(); },
             () -> null,
@@ -129,7 +133,7 @@
             () -> 2);
         solveAny(cachedThreadPool, solvers);
         assertEquals(1, results.size());
-        Integer elt = results.iterator().next();
+        Integer elt = results.get(0);
         assertTrue(elt.equals(1) || elt.equals(2));
     }
 
--- a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java	Wed Jul 05 22:32:06 2017 +0200
@@ -36,7 +36,8 @@
 /*
  * @test
  * @summary JSR-166 tck tests
- * @modules java.management
+ * @modules java.base/java.util.concurrent:open
+ *          java.management
  * @build *
  * @run junit/othervm/timeout=1000 -Djsr166.testImplementationDetails=true JSR166TestCase
  * @run junit/othervm/timeout=1000 -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 -Djsr166.testImplementationDetails=true JSR166TestCase
@@ -68,6 +69,7 @@
 import java.security.SecurityPermission;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
@@ -474,6 +476,7 @@
             AbstractQueuedLongSynchronizerTest.suite(),
             ArrayBlockingQueueTest.suite(),
             ArrayDequeTest.suite(),
+            ArrayListTest.suite(),
             AtomicBooleanTest.suite(),
             AtomicIntegerArrayTest.suite(),
             AtomicIntegerFieldUpdaterTest.suite(),
@@ -496,6 +499,7 @@
             CopyOnWriteArrayListTest.suite(),
             CopyOnWriteArraySetTest.suite(),
             CountDownLatchTest.suite(),
+            CountedCompleterTest.suite(),
             CyclicBarrierTest.suite(),
             DelayQueueTest.suite(),
             EntryTest.suite(),
@@ -524,15 +528,17 @@
             TreeMapTest.suite(),
             TreeSetTest.suite(),
             TreeSubMapTest.suite(),
-            TreeSubSetTest.suite());
+            TreeSubSetTest.suite(),
+            VectorTest.suite());
 
         // Java8+ test classes
         if (atLeastJava8()) {
             String[] java8TestClassNames = {
+                "ArrayDeque8Test",
                 "Atomic8Test",
                 "CompletableFutureTest",
                 "ConcurrentHashMap8Test",
-                "CountedCompleterTest",
+                "CountedCompleter8Test",
                 "DoubleAccumulatorTest",
                 "DoubleAdderTest",
                 "ForkJoinPool8Test",
@@ -1850,12 +1856,22 @@
         }
     }
 
+    void assertImmutable(final Object o) {
+        if (o instanceof Collection) {
+            assertThrows(
+                UnsupportedOperationException.class,
+                new Runnable() { public void run() {
+                        ((Collection) o).add(null);}});
+        }
+    }
+
     @SuppressWarnings("unchecked")
     <T> T serialClone(T o) {
         try {
             ObjectInputStream ois = new ObjectInputStream
                 (new ByteArrayInputStream(serialBytes(o)));
             T clone = (T) ois.readObject();
+            if (o == clone) assertImmutable(o);
             assertSame(o.getClass(), clone.getClass());
             return clone;
         } catch (Throwable fail) {
@@ -1864,6 +1880,46 @@
         }
     }
 
+    /**
+     * A version of serialClone that leaves error handling (for
+     * e.g. NotSerializableException) up to the caller.
+     */
+    @SuppressWarnings("unchecked")
+    <T> T serialClonePossiblyFailing(T o)
+        throws ReflectiveOperationException, java.io.IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(o);
+        oos.flush();
+        oos.close();
+        ObjectInputStream ois = new ObjectInputStream
+            (new ByteArrayInputStream(bos.toByteArray()));
+        T clone = (T) ois.readObject();
+        if (o == clone) assertImmutable(o);
+        assertSame(o.getClass(), clone.getClass());
+        return clone;
+    }
+
+    /**
+     * If o implements Cloneable and has a public clone method,
+     * returns a clone of o, else null.
+     */
+    @SuppressWarnings("unchecked")
+    <T> T cloneableClone(T o) {
+        if (!(o instanceof Cloneable)) return null;
+        final T clone;
+        try {
+            clone = (T) o.getClass().getMethod("clone").invoke(o);
+        } catch (NoSuchMethodException ok) {
+            return null;
+        } catch (ReflectiveOperationException unexpected) {
+            throw new Error(unexpected);
+        }
+        assertNotSame(o, clone); // not 100% guaranteed by spec
+        assertSame(o.getClass(), clone.getClass());
+        return clone;
+    }
+
     public void assertThrows(Class<? extends Throwable> expectedExceptionClass,
                              Runnable... throwingActions) {
         for (Runnable throwingAction : throwingActions) {
--- a/jdk/test/java/util/concurrent/tck/LinkedBlockingDequeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/LinkedBlockingDequeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -68,14 +68,22 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return LinkedBlockingDeque.class; }
+            public Collection emptyCollection() { return new LinkedBlockingDeque(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(LinkedBlockingDequeTest.class,
                             new Unbounded().testSuite(),
-                            new Bounded().testSuite());
+                            new Bounded().testSuite(),
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new deque of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private LinkedBlockingDeque<Integer> populatedDeque(int n) {
         LinkedBlockingDeque<Integer> q =
@@ -86,6 +94,8 @@
         assertFalse(q.isEmpty());
         assertEquals(0, q.remainingCapacity());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peekFirst());
+        assertEquals((Integer) (n - 1), q.peekLast());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/LinkedBlockingQueueTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/LinkedBlockingQueueTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -68,14 +68,22 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return LinkedBlockingQueue.class; }
+            public Collection emptyCollection() { return new LinkedBlockingQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(LinkedBlockingQueueTest.class,
                             new Unbounded().testSuite(),
-                            new Bounded().testSuite());
+                            new Bounded().testSuite(),
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private LinkedBlockingQueue<Integer> populatedQueue(int n) {
         LinkedBlockingQueue<Integer> q =
@@ -86,6 +94,7 @@
         assertFalse(q.isEmpty());
         assertEquals(0, q.remainingCapacity());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/LinkedListTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/LinkedListTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -48,12 +48,27 @@
     }
 
     public static Test suite() {
-        return new TestSuite(LinkedListTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return LinkedList.class; }
+            public Collection emptyCollection() { return new LinkedList(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return true; }
+        }
+        class SubListImplementation extends Implementation {
+            public Collection emptyCollection() {
+                return new LinkedList().subList(0, 0);
+            }
+        }
+        return newTestSuite(
+                LinkedListTest.class,
+                CollectionTest.testSuite(new Implementation()),
+                CollectionTest.testSuite(new SubListImplementation()));
     }
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private LinkedList<Integer> populatedQueue(int n) {
         LinkedList<Integer> q = new LinkedList<Integer>();
@@ -62,6 +77,8 @@
             assertTrue(q.offer(new Integer(i)));
         assertFalse(q.isEmpty());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peekFirst());
+        assertEquals((Integer) (n - 1), q.peekLast());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/LinkedTransferQueueTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/LinkedTransferQueueTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -51,14 +51,6 @@
 
 @SuppressWarnings({"unchecked", "rawtypes"})
 public class LinkedTransferQueueTest extends JSR166TestCase {
-    static class Implementation implements CollectionImplementation {
-        public Class<?> klazz() { return LinkedTransferQueue.class; }
-        public Collection emptyCollection() { return new LinkedTransferQueue(); }
-        public Object makeElement(int i) { return i; }
-        public boolean isConcurrent() { return true; }
-        public boolean permitsNulls() { return false; }
-    }
-
     public static class Generic extends BlockingQueueTest {
         protected BlockingQueue emptyCollection() {
             return new LinkedTransferQueue();
@@ -70,6 +62,13 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return LinkedTransferQueue.class; }
+            public Collection emptyCollection() { return new LinkedTransferQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(LinkedTransferQueueTest.class,
                             new Generic().testSuite(),
                             CollectionTest.testSuite(new Implementation()));
--- a/jdk/test/java/util/concurrent/tck/PriorityBlockingQueueTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/PriorityBlockingQueueTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,9 +69,17 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return PriorityBlockingQueue.class; }
+            public Collection emptyCollection() { return new PriorityBlockingQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(PriorityBlockingQueueTest.class,
                             new Generic().testSuite(),
-                            new InitialCapacity().testSuite());
+                            new InitialCapacity().testSuite(),
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /** Sample Comparator */
@@ -83,7 +91,7 @@
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private PriorityBlockingQueue<Integer> populatedQueue(int n) {
         PriorityBlockingQueue<Integer> q =
@@ -96,6 +104,7 @@
         assertFalse(q.isEmpty());
         assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/PriorityQueueTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/PriorityQueueTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -49,7 +49,15 @@
         main(suite(), args);
     }
     public static Test suite() {
-        return new TestSuite(PriorityQueueTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return PriorityQueue.class; }
+            public Collection emptyCollection() { return new PriorityQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return false; }
+        }
+        return newTestSuite(PriorityQueueTest.class,
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     static class MyReverseComparator implements Comparator {
@@ -60,7 +68,7 @@
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private PriorityQueue<Integer> populatedQueue(int n) {
         PriorityQueue<Integer> q = new PriorityQueue<Integer>(n);
@@ -71,6 +79,7 @@
             assertTrue(q.offer(new Integer(i)));
         assertFalse(q.isEmpty());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/StampedLockTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/StampedLockTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -110,12 +110,12 @@
 
     List<Function<StampedLock, Long>> readLockers() {
         List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
-        readLockers.add((sl) -> sl.readLock());
-        readLockers.add((sl) -> sl.tryReadLock());
-        readLockers.add((sl) -> readLockInterruptiblyUninterrupted(sl));
-        readLockers.add((sl) -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
-        readLockers.add((sl) -> tryReadLockUninterrupted(sl, 0L, DAYS));
-        readLockers.add((sl) -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
+        readLockers.add(sl -> sl.readLock());
+        readLockers.add(sl -> sl.tryReadLock());
+        readLockers.add(sl -> readLockInterruptiblyUninterrupted(sl));
+        readLockers.add(sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+        readLockers.add(sl -> tryReadLockUninterrupted(sl, 0L, DAYS));
+        readLockers.add(sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
         return readLockers;
     }
 
@@ -131,12 +131,12 @@
 
     List<Function<StampedLock, Long>> writeLockers() {
         List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
-        writeLockers.add((sl) -> sl.writeLock());
-        writeLockers.add((sl) -> sl.tryWriteLock());
-        writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
-        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
-        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0L, DAYS));
-        writeLockers.add((sl) -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
+        writeLockers.add(sl -> sl.writeLock());
+        writeLockers.add(sl -> sl.tryWriteLock());
+        writeLockers.add(sl -> writeLockInterruptiblyUninterrupted(sl));
+        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, 0L, DAYS));
+        writeLockers.add(sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
         return writeLockers;
     }
 
--- a/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -963,7 +963,7 @@
         AtomicInteger sum = new AtomicInteger();
         SubmissionPublisher<Integer> p = basicPublisher();
         CompletableFuture<Void> f =
-            p.consume((Integer x) -> { sum.getAndAdd(x.intValue()); });
+            p.consume((Integer x) -> sum.getAndAdd(x.intValue()));
         int n = 20;
         for (int i = 1; i <= n; ++i)
             p.submit(i);
--- a/jdk/test/java/util/concurrent/tck/ThreadLocalRandom8Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ThreadLocalRandom8Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -259,4 +259,20 @@
         assertEquals(size, counter.sum());
     }
 
+    /**
+     * A deserialized ThreadLocalRandom is always identical to
+     * ThreadLocalRandom.current()
+     */
+    public void testSerialization() {
+        assertSame(
+            ThreadLocalRandom.current(),
+            serialClone(ThreadLocalRandom.current()));
+        // In the current implementation, there is exactly one shared instance
+        if (testImplementationDetails)
+            assertSame(
+                ThreadLocalRandom.current(),
+                java.util.concurrent.CompletableFuture.supplyAsync(
+                    () -> serialClone(ThreadLocalRandom.current())).join());
+    }
+
 }
--- a/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -79,6 +79,41 @@
     }
 
     /**
+     * Repeated calls to next (only accessible via reflection) produce
+     * at least two distinct results, and repeated calls produce all
+     * possible values.
+     */
+    public void testNext() throws ReflectiveOperationException {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        try {
+            java.lang.reflect.Method m
+                = ThreadLocalRandom.class.getDeclaredMethod(
+                    "next", new Class[] { int.class });
+            m.setAccessible(true);
+
+            int i;
+            {
+                int val = new java.util.Random().nextInt(4);
+                for (i = 0; i < NCALLS; i++) {
+                    int q = (int) m.invoke(rnd, new Object[] { 2 });
+                    if (val == q) break;
+                }
+                assertTrue(i < NCALLS);
+            }
+
+            {
+                int r = (int) m.invoke(rnd, new Object[] { 3 });
+                for (i = 0; i < NCALLS; i++) {
+                    int q = (int) m.invoke(rnd, new Object[] { 3 });
+                    assertTrue(q < (1<<3));
+                    if (r != q) break;
+                }
+                assertTrue(i < NCALLS);
+            }
+        } catch (SecurityException acceptable) {}
+    }
+
+    /**
      * Repeated calls to nextInt produce at least two distinct results
      */
     public void testNextInt() {
--- a/jdk/test/java/util/concurrent/tck/TreeSetTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/TreeSetTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -67,7 +67,7 @@
 
     /**
      * Returns a new set of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private TreeSet<Integer> populatedSet(int n) {
         TreeSet<Integer> q = new TreeSet<Integer>();
--- a/jdk/test/java/util/concurrent/tck/TreeSubSetTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/concurrent/tck/TreeSubSetTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -58,7 +58,7 @@
 
     /**
      * Returns a new set of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private NavigableSet<Integer> populatedSet(int n) {
         TreeSet<Integer> q = new TreeSet<Integer>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/VectorTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Vector;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class VectorTest extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return Vector.class; }
+            public List emptyCollection() { return new Vector(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return true; }
+        }
+        class SubListImplementation extends Implementation {
+            public List emptyCollection() {
+                return super.emptyCollection().subList(0, 0);
+            }
+        }
+        return newTestSuite(
+                // VectorTest.class,
+                CollectionTest.testSuite(new Implementation()),
+                CollectionTest.testSuite(new SubListImplementation()));
+    }
+
+}
--- a/jdk/test/java/util/logging/FileHandlerLongLimit.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/logging/FileHandlerLongLimit.java	Wed Jul 05 22:32:06 2017 +0200
@@ -52,6 +52,7 @@
  * @test
  * @bug 8059767
  * @summary tests that FileHandler can accept a long limit.
+ * @modules java.logging/java.util.logging:open
  * @run main/othervm FileHandlerLongLimit UNSECURE
  * @run main/othervm FileHandlerLongLimit SECURE
  * @author danielfuchs
--- a/jdk/test/java/util/logging/HandlersConfigTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/logging/HandlersConfigTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,7 @@
  *          configured correctly from defaults and/or LogManager properties
  *          as specified in javadoc and that no special
  *          logging permission is required for instantiating them.
+ * @modules java.logging/java.util.logging:open
  * @run main/othervm HandlersConfigTest default
  * @run main/othervm HandlersConfigTest configured
  */
--- a/jdk/test/java/util/logging/LocalizedLevelName.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/logging/LocalizedLevelName.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
  * @test
  * @bug 8016127 8024131
  * @summary test logging.properties localized
+ * @modules java.logging/sun.util.logging.resources:open
  * @run main/othervm LocalizedLevelName
  */
 
--- a/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -61,6 +61,7 @@
  * @test
  * @bug 8033661
  * @summary tests LogManager.updateConfiguration(bin)
+ * @modules java.logging/java.util.logging:open
  * @run main/othervm UpdateConfigurationTest UNSECURE
  * @run main/othervm UpdateConfigurationTest SECURE
  * @author danielfuchs
--- a/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -136,10 +136,6 @@
         // class resource bundle in another named module m1.
         failToLoadResourceBundle("mylogger.g", "p1.resource.ClassResource",
                 true, NAMED_NEGATIVE_CLASSBUNDLE_MSG);
-        // in named module m2, try to create a logger with
-        // class resource bundle in an unnamed module.
-        failToLoadResourceBundle("mylogger.h", "p3.resource.ClassResource",
-                true, NAMED_NEGATIVE_CLASSBUNDLE_MSG);
     }
 
     static void failToLoadPropertyRBs() {
@@ -153,10 +149,6 @@
         // property resource bundle in another named module m1.
         failToLoadResourceBundle("mylogger.k", "p1.resource.p",
                 true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG);
-        // in named module m2, try to create a logger with
-        // property resource bundle in an unnamed module.
-        failToLoadResourceBundle("mylogger.l", "p3.resource.p",
-                true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG);
     }
 
     static void failToLoadResourceBundle(String loggerName, String rbName,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/crypto/CryptoPermissions/CryptoPolicyFallback.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8169335
+ * @summary Add a crypto policy fallback in case Security Property
+ * 'crypto.policy' does not exist.
+ * @run main/othervm CryptoPolicyFallback
+ */
+import java.io.*;
+import java.nio.file.*;
+import java.util.stream.*;
+import javax.crypto.*;
+
+/*
+ * Take the current java.security file, strip out the 'crypto.policy' entry,
+ * write to a new file in the current directory, then use that file as the
+ * replacement java.security file.  This test will fail if the crypto.policy
+ * entry doesn't match the compiled in value.
+ */
+public class CryptoPolicyFallback {
+
+    private static final String FILENAME = "java.security";
+
+    public static void main(String[] args) throws Exception {
+
+        String javaHome = System.getProperty("java.home");
+
+        Path path = Paths.get(javaHome, "conf", "security", FILENAME);
+
+        /*
+         * Get the default value.
+         */
+        String defaultPolicy;
+        try (Stream<String> lines = Files.lines(path)) {
+            /*
+             * If the input java.security file is malformed
+             * (missing crypto.policy, attribute/no value, etc), throw
+             * exception.  split() might throw AIOOB which
+             * is ok behavior.
+             */
+            defaultPolicy = lines.filter(x -> x.startsWith("crypto.policy="))
+                    .findFirst().orElseThrow(
+                            () -> new Exception("Missing crypto.policy"))
+                    .split("=")[1].trim();
+        }
+
+        /*
+         * We know there is at least one crypto.policy entry, strip
+         * all of them out of the java.security file.
+         */
+        try (PrintWriter out = new PrintWriter(FILENAME);
+                Stream<String> lines = Files.lines(path)) {
+            lines.filter(x -> !x.trim().startsWith("crypto.policy="))
+                    .forEach(out::println);
+        }
+
+        /*
+         * "-Djava.security.properties==file" does a complete replacement
+         * of the system java.security file.  i.e. value must be "=file"
+         */
+        System.setProperty("java.security.properties", "=" + FILENAME);
+
+        /*
+         * Find out expected value.
+         */
+        int expected;
+        switch (defaultPolicy) {
+        case "limited":
+            expected = 128;
+            break;
+        case "unlimited":
+            expected = Integer.MAX_VALUE;
+            break;
+        default:
+            throw new Exception(
+                    "Unexpected Default Policy Value: " + defaultPolicy);
+        }
+
+        /*
+         * Do the actual check.  If the JCE Framework can't initialize
+         * an Exception is normally thrown here.
+         */
+        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
+
+        System.out.println("Default Policy: " + defaultPolicy
+                + "\nExpected max AES key length: " + expected
+                + ", received : " + maxKeyLen);
+
+        if (expected != maxKeyLen) {
+            throw new Exception("Wrong Key Length size!");
+        }
+
+        System.out.println("PASSED!");
+    }
+}
--- a/jdk/test/javax/crypto/CryptoPermissions/TestUnlimited.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/crypto/CryptoPermissions/TestUnlimited.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,10 +27,11 @@
  * @test
  * @bug 8061842
  * @summary Package jurisdiction policy files as something other than JAR
+ * @run main/othervm TestUnlimited use_default default
  * @run main/othervm TestUnlimited "" exception
- * @run main/othervm TestUnlimited limited fail
- * @run main/othervm TestUnlimited unlimited pass
- * @run main/othervm TestUnlimited unlimited/ pass
+ * @run main/othervm TestUnlimited limited limited
+ * @run main/othervm TestUnlimited unlimited unlimited
+ * @run main/othervm TestUnlimited unlimited/ unlimited
  * @run main/othervm TestUnlimited NosuchDir exception
  * @run main/othervm TestUnlimited . exception
  * @run main/othervm TestUnlimited /tmp/unlimited exception
@@ -40,9 +41,38 @@
  */
 import javax.crypto.*;
 import java.security.Security;
+import java.nio.file.*;
+import java.util.stream.*;
 
 public class TestUnlimited {
 
+    private enum Result {
+        UNLIMITED,
+        LIMITED,
+        EXCEPTION,
+        UNKNOWN
+    };
+
+    /*
+     * Grab the default policy entry from java.security.
+     *
+     * If the input java.security file is malformed
+     * (missing crypto.policy, attribute/no value, etc), throw
+     * exception.  split() might throw AIOOB which
+     * is ok behavior.
+     */
+    private static String getDefaultPolicy() throws Exception {
+        String javaHome = System.getProperty("java.home");
+        Path path = Paths.get(javaHome, "conf", "security", "java.security");
+
+        try (Stream<String> lines = Files.lines(path)) {
+            return lines.filter(x -> x.startsWith("crypto.policy="))
+                    .findFirst().orElseThrow(
+                            () -> new Exception("Missing crypto.policy"))
+                    .split("=")[1].trim();
+        }
+    }
+
     public static void main(String[] args) throws Exception {
         /*
          * Override the Security property to allow for unlimited policy.
@@ -53,16 +83,37 @@
             throw new Exception("Two args required");
         }
 
-        boolean expected = args[1].equals("pass");
-        boolean exception = args[1].equals("exception");
-        boolean result = false;
+        String testStr = args[0];
+        String expectedStr = args[1];
+        if (testStr.equals("use_default")) {
+            expectedStr = getDefaultPolicy();
+        }
+
+        Result expected = Result.UNKNOWN;  // avoid NPE warnings
+        Result result;
 
-        System.out.println("Testing: " + args[0]);
+        switch (expectedStr) {
+        case "unlimited":
+            expected = Result.UNLIMITED;
+            break;
+        case "limited":
+            expected = Result.LIMITED;
+            break;
+        case "exception":
+            expected = Result.EXCEPTION;
+            break;
+        default:
+            throw new Exception("Unexpected argument");
+        }
 
-        if (args[0].equals("\"\"")) {
+        System.out.println("Testing: " + testStr);
+        if (testStr.equals("\"\"")) {
             Security.setProperty("crypto.policy", "");
         } else {
-            Security.setProperty("crypto.policy", args[0]);
+            // skip default case.
+            if (!testStr.equals("use_default")) {
+                Security.setProperty("crypto.policy", testStr);
+            }
         }
 
         /*
@@ -74,21 +125,20 @@
             System.out.println("max AES key len:" + maxKeyLen);
             if (maxKeyLen > 128) {
                 System.out.println("Unlimited policy is active");
-                result = true;
+                result = Result.UNLIMITED;
             } else {
                 System.out.println("Unlimited policy is NOT active");
-                result = false;
+                result = Result.LIMITED;
             }
         } catch (Throwable e) {
-            if (!exception) {
-                throw new Exception();
-            }
+            //ExceptionInInitializerError's
+            result = Result.EXCEPTION;
         }
 
         System.out.println(
                 "Expected:\t" + expected + "\nResult:\t\t" + result);
-        if (expected != result) {
-            throw new Exception();
+        if (!expected.equals(result)) {
+            throw new Exception("Didn't match");
         }
 
         System.out.println("DONE!");
--- a/jdk/test/javax/management/ObjectName/CompressedStorageTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/management/ObjectName/CompressedStorageTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,7 @@
  * @summary Tests the limits imposed on the domain name part of an
  *          ObjectName instance
  * @author Jaroslav Bachorik
- * @modules java.management
+ * @modules java.management/javax.management:open
  * @run main CompressedStorageTest
  */
 
--- a/jdk/test/javax/management/loading/MLetInternalsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/management/loading/MLetInternalsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -36,7 +36,7 @@
  * @bug 8058089
  * @summary Tests various internal functions provided by MLet for correctness
  * @author Jaroslav Bachorik
- * @modules java.management
+ * @modules java.management/javax.management.loading:open
  * @run testng MLetInternalsTest
  */
 public class MLetInternalsTest {
--- a/jdk/test/javax/management/openmbean/TabularDataOrderTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/management/openmbean/TabularDataOrderTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6334663
  * @summary Test that TabularDataSupport preserves the order elements were added
  * @author Eamonn McManus
- * @modules java.management
+ * @modules java.management/javax.management.openmbean:open
  */
 
 import java.io.ByteArrayInputStream;
--- a/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,7 +29,7 @@
  *          thrown when constructor is invoked with null class loader as
  *          an argument.
  * @author Amit Sapre
- * @modules java.management
+ * @modules java.management/javax.management.remote.rmi:open
  * @run clean ObjectInputStreamWithLoaderNullCheckTest
  * @run build ObjectInputStreamWithLoaderNullCheckTest
  * @run main ObjectInputStreamWithLoaderNullCheckTest
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectionIdTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectionIdTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 4901808 7183800
- * @summary Check that RMI connection ids include client host name
+ * @summary Check that RMI connection ids include IP address of a client network interface
  * @author Eamonn McManus
  * @modules java.management
  * @run clean RMIConnectionIdTest
@@ -39,7 +39,7 @@
 public class RMIConnectionIdTest {
     public static void main(String[] args) throws Exception {
         System.out.println("Testing that RMI connection id includes " +
-                           "client host name");
+                           "IP address of a client network interface");
         MBeanServer mbs = MBeanServerFactory.createMBeanServer();
         JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
         JMXConnectorServer cs =
@@ -61,11 +61,9 @@
         }
         String clientAddr = rest.substring(0, spaceIndex);
         InetAddress clientInetAddr = InetAddress.getByName(clientAddr);
-        InetAddress localAddr = clientInetAddr.isLoopbackAddress() ? InetAddress.getLoopbackAddress() : InetAddress.getLocalHost();
-        System.out.println("InetAddresses: local=" + localAddr + "; " +
-                           "connectionId=" + clientInetAddr);
-        if (!localAddr.equals(clientInetAddr)) {
-            System.out.println("TEST FAILS: addresses differ");
+        NetworkInterface ni = NetworkInterface.getByInetAddress(clientInetAddr);
+        if (ni == null) {
+            System.out.println("TEST FAILS: address not found");
             System.exit(1);
         }
         cc.close();
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -42,7 +42,7 @@
  * @bug 6566891
  * @summary Check no memory leak on RMIConnector's rmbscMap
  * @author Shanliang JIANG
- * @modules java.management
+ * @modules java.management/javax.management.remote.rmi:open
  * @run clean RMIConnectorInternalMapTest
  * @run build RMIConnectorInternalMapTest
  * @run main RMIConnectorInternalMapTest
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -38,7 +38,7 @@
  * @bug 6566891
  * @summary Check no memory leak on RMIConnector's nullSubjectConn
  * @author Shanliang JIANG
- * @modules java.management
+ * @modules java.management/javax.management.remote.rmi:open
  * @run clean RMIConnectorNullSubjectConnTest
  * @run build RMIConnectorNullSubjectConnTest
  * @run main RMIConnectorNullSubjectConnTest
--- a/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,8 @@
  * @test
  * @bug 6957378
  * @summary Test that a listener can be removed remotely from an MBean that no longer exists.
- * @modules java.management/com.sun.jmx.remote.internal
+ * @modules java.management/javax.management.remote.rmi:open
+ *          java.management/com.sun.jmx.remote.internal:+open
  * @author Eamonn McManus
  * @run main/othervm -XX:+UsePerfData DeadListenerTest
  */
--- a/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,8 +30,8 @@
  * @modules java.security.jgss
  *          jdk.security.auth
  *          java.base/sun.security.util
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
  *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
--- a/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,10 +27,10 @@
  * @summary Testing DTLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS DTLSNotEnabledRC4Test
--- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,10 +28,10 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS DTLSUnsupportedCiphersTest
--- a/jdk/test/javax/net/ssl/DTLS/TEST.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLS/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -1,7 +1,7 @@
 modules = \
-    java.security.jgss/sun.security.krb5 \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.security.jgss/sun.security.krb5.internal.ktab \
     java.base/sun.security.util
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,10 +27,10 @@
  * @summary Testing DTLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0 DTLSv10NotEnabledRC4Test
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,10 +28,10 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/TEST.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/DTLSv10/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -1,7 +1,7 @@
 modules = \
-    java.security.jgss/sun.security.krb5 \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.security.jgss/sun.security.krb5.internal.ktab \
     java.base/sun.security.util
--- a/jdk/test/javax/net/ssl/TLS/TEST.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -1,8 +1,8 @@
 modules = \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ktab \
-    java.security.jgss/sun.security.krb5 \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.base/sun.security.util \
     jdk.crypto.ec/sun.security.ec
--- a/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,11 +28,11 @@
  * @summary javax/net/ssl/TLS/TLSClientPropertyTest.java needs to be
  *     updated for JDK-8061210
  * @modules java.security.jgss
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm TLSClientPropertyTest NoProperty
  * @run main/othervm TLSClientPropertyTest SSLv3
--- a/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,11 +29,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSDataExchangeTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSDataExchangeTest
--- a/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,11 +29,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSEnginesClosureTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSEnginesClosureTest
--- a/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,11 +29,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSHandshakeTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSHandshakeTest
--- a/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,11 +30,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSMFLNTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSMFLNTest
--- a/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,11 +27,11 @@
  * @summary Testing TLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS TLSNotEnabledRC4Test
  */
--- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,11 +29,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSRehandshakeTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSRehandshakeTest
--- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,11 +29,11 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS TLSRehandshakeWithCipherChangeTest
  */
--- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,11 +30,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSRehandshakeWithDataExTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSRehandshakeWithDataExTest
--- a/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,11 +28,11 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS TLSUnsupportedCiphersTest
  */
--- a/jdk/test/javax/net/ssl/TLSv1/TEST.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -1,7 +1,7 @@
 modules = \
-    java.security.jgss/sun.security.krb5 \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.security.jgss/sun.security.krb5.internal.ktab \
     java.base/sun.security.util
--- a/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSDataExchangeTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSEnginesClosureTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSHandshakeTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSMFLNTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,10 +27,10 @@
  * @summary Testing TLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 TLSNotEnabledRC4Test
--- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSRehandshakeTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 TLSRehandshakeWithCipherChangeTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSRehandshakeWithDataExTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,10 +28,10 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 TLSUnsupportedCiphersTest
--- a/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,10 +34,10 @@
  * @summary Support TLS 1.1
  * @run main/othervm EmptyCertificateAuthorities
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @author Xuelei Fan
--- a/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,10 +34,10 @@
  * @summary Support TLS 1.1
  * @run main/othervm ExportableBlockCipher
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @author Xuelei Fan
--- a/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Wed Jul 05 22:32:06 2017 +0200
@@ -33,10 +33,10 @@
  * @bug 4873188
  * @summary Support TLS 1.1
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm ExportableStreamCipher
--- a/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,10 +28,10 @@
  * @bug 4873188
  * @summary Support TLS 1.1
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm GenericBlockCipher
--- a/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,10 +28,10 @@
  * @bug 4873188
  * @summary Support TLS 1.1
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm GenericStreamCipher
--- a/jdk/test/javax/net/ssl/TLSv11/TEST.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -1,7 +1,7 @@
 modules = \
-    java.security.jgss/sun.security.krb5 \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.security.jgss/sun.security.krb5.internal.ktab \
     java.base/sun.security.util
--- a/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSDataExchangeTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSEnginesClosureTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSHandshakeTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSMFLNTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,10 +27,10 @@
  * @summary Testing TLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSNotEnabledRC4Test
--- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSRehandshakeTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,10 +29,10 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSRehandshakeWithCipherChangeTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSRehandshakeWithDataExTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,10 +28,10 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSUnsupportedCiphersTest
--- a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,7 +23,7 @@
 
 /* @test
    @summary Test SoftSynthesizer implicit open/close using getReceiver.
-   @modules java.desktop/com.sun.media.sound
+   @modules java.desktop/com.sun.media.sound:+open
 */
 
 import java.lang.reflect.Field;
--- a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,7 +23,7 @@
 
 /* @test
    @summary Test SoftSynthesizer open method
-   @modules java.desktop/com.sun.media.sound
+   @modules java.desktop/com.sun.media.sound:+open
 */
 
 import java.lang.reflect.Field;
--- a/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,6 +25,7 @@
    @bug 6688203
    @summary Memory leak and performance problems in the method getFileSystemView of FileSystemView
    @author Pavel Porvatov
+   @modules java.desktop/javax.swing.filechooser:open
    @run main bug6688203
 */
 
--- a/jdk/test/javax/swing/JLabel/7004134/bug7004134.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/JLabel/7004134/bug7004134.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,7 @@
  * @summary JLabel containing a ToolTipText does no longer show ToolTip after browser refresh
  * @author Pavel Porvatov
  * @modules java.desktop/sun.awt
+ * @modules java.desktop/javax.swing:open
  */
 
 import sun.awt.SunToolkit;
--- a/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,6 +30,7 @@
  * @author Sergey Malenkov
  * @library ../..
  * @modules java.desktop/sun.awt
+ * @modules java.desktop/javax.swing.plaf.basic:open
  */
 
 import sun.awt.AppContext;
--- a/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,7 @@
  * @bug 6800513
  * @summary GTK-LaF renders menus incompletely
  * @author Mario Torre
+ * @modules java.desktop/javax.swing:open
  * @library ../../regtesthelpers/
  * @build Util
  * @run main bug6800513
--- a/jdk/test/javax/swing/JSlider/6794836/bug6794836.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/JSlider/6794836/bug6794836.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,6 +27,7 @@
  * @bug 6794836
  * @summary BasicSliderUI throws NullPointerExc when JSlider maximum is Integer.MAX_VALUE
  * @author Pavel Porvatov
+ * @modules java.desktop/javax.swing.plaf.basic:open
  * @run main bug6794836
  */
 
--- a/jdk/test/javax/swing/JSlider/6848475/bug6848475.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/JSlider/6848475/bug6848475.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,6 +27,7 @@
  * @bug 6848475
  * @summary JSlider does not display the correct value of its BoundedRangeModel
  * @author Pavel Porvatov
+ * @modules java.desktop/javax.swing.plaf.basic:open
  * @run main bug6848475
  */
 
--- a/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,6 +29,7 @@
 /* @test
    @bug 7010561
    @summary Tab text position with Synth based LaF is different to Java 5/6
+   @modules java.desktop/javax.swing.plaf.basic:open
    @author Pavel Porvatov
 */
 public class bug7010561 {
--- a/jdk/test/javax/swing/JTree/6263446/bug6263446.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/JTree/6263446/bug6263446.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,6 +27,7 @@
  * @bug 6263446
  * @summary Tests that double-clicking to edit a cell doesn't select the content.
  * @author Shannon Hickey
+ * @modules java.desktop/javax.swing.tree:open
  * @run main bug6263446
  */
 import java.awt.*;
--- a/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,6 +24,7 @@
 /* @test
    @bug 7013453
    @summary BufferStrategyPaintManager.dispose will cause IllegalMonitorStateException in event thread
+   @modules java.desktop/javax.swing:open
    @author Pavel Porvatov
 */
 
--- a/jdk/test/javax/swing/Security/6938813/bug6938813.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/Security/6938813/bug6938813.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
  * @bug 6938813
  * @summary Swing mutable statics
  * @author Pavel Porvatov
+ * @modules java.desktop/javax.swing.text.html.parser:open
  * @modules java.desktop/sun.awt
  */
 
--- a/jdk/test/javax/swing/border/Test7149090.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/border/Test7149090.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,6 +24,7 @@
 /* @test
    @bug 7149090
    @summary Nimbus:BorderFactory.createTitledBorder() the DEFAULT position of a title is not the same as the TOP
+   @modules java.desktop/javax.swing.border:open
    @author Pavel Porvatov
 */
 
--- a/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
  * @bug 7143614
  * @summary Issues with Synth Look&Feel
  * @author Pavel Porvatov
+ * @modules java.desktop/javax.swing.plaf.synth:open
  * @modules java.desktop/sun.awt
  */
 
--- a/jdk/test/javax/swing/text/View/8014863/bug8014863.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/swing/text/View/8014863/bug8014863.java	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,7 @@
  * @bug 8024395
  * @summary  Tests the calculation of the line breaks when a text is inserted
  * @author Dmitry Markov
+ * @modules java.desktop/javax.swing.text:open
  * @library ../../../regtesthelpers
  * @build Util
  * @run main bug8014863
--- a/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java	Wed Jul 05 22:32:06 2017 +0200
@@ -30,7 +30,7 @@
  *      correctly maps them to their preferred mime names.
  *      Also checks that the Encodings.properties resource file
  *      is consistent.
- * @modules java.xml/com.sun.org.apache.xml.internal.serializer
+ * @modules java.xml/com.sun.org.apache.xml.internal.serializer:+open
  * @compile -XDignore.symbol.file CheckEncodingPropertiesFile.java
  * @run main CheckEncodingPropertiesFile
  * @author Daniel Fuchs
--- a/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java	Wed Jul 05 22:32:06 2017 +0200
@@ -31,7 +31,7 @@
  *   in com.sun.org.apache.xerces.internal.impl.dv.xs.PrecisionDecimalDV$XPrecisionDecimal.
  *   Since that method is private the test unfortunately needs to use reflection
  *   to invoke the method.
- * @modules java.xml/com.sun.org.apache.xerces.internal.impl.dv.xs
+ * @modules java.xml/com.sun.org.apache.xerces.internal.impl.dv.xs:open
  * @run main XPrecisionDecimalToString
  * @author Daniel Fuchs
  */
--- a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8080679 8131913
  * @modules jdk.internal.le/jdk.internal.jline
- *          jdk.internal.le/jdk.internal.jline.console
+ *          jdk.internal.le/jdk.internal.jline.console:+open
  * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly.
  */
 
--- a/jdk/test/jdk/internal/jrtfs/remote/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/jdk/internal/jrtfs/remote/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -68,7 +68,7 @@
     }
 
     private static FileSystem createFsWithURLClassloader(String javaHome) throws IOException{
-        URL url = Paths.get(javaHome, "jrt-fs.jar").toUri().toURL();
+        URL url = Paths.get(javaHome, "lib", "jrt-fs.jar").toUri().toURL();
         URLClassLoader loader = new URLClassLoader(new URL[] { url });
         return FileSystems.newFileSystem(URI.create("jrt:/"),
                                                     Collections.emptyMap(),
--- a/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -64,7 +64,7 @@
         String java = jdk8Path.resolve("bin/java").toAbsolutePath().toString();
         String javac = jdk8Path.resolve("bin/javac").toAbsolutePath().toString();
         Files.createDirectories(Paths.get(".", CLASSES_DIR));
-        String jrtJar = Paths.get(TEST_JAVAHOME, JRTFS_JAR).toAbsolutePath().toString();
+        String jrtJar = Paths.get(TEST_JAVAHOME, "lib", JRTFS_JAR).toAbsolutePath().toString();
 
         // Compose command-lines for compiling and executing tests
         List<List<String>> cmds = Arrays.asList(
--- a/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,7 +22,6 @@
  */
 
 import jdk.internal.misc.Unsafe;
-import java.lang.reflect.Field;
 
 /**
  * Helper class to support testing of Unsafe.copyMemory and Unsafe.copySwapMemory
@@ -37,17 +36,7 @@
     static final int SMALL_COPY_SIZE = 32;
     static final int BASE_ALIGNMENT = 16;
 
-    protected static final Unsafe UNSAFE;
-
-    static {
-        try {
-            Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe");
-            f.setAccessible(true);
-            UNSAFE = (jdk.internal.misc.Unsafe) f.get(null);
-        } catch (Exception e) {
-            throw new RuntimeException("Unable to get Unsafe instance.", e);
-        }
-    }
+    protected static final Unsafe UNSAFE = Unsafe.getUnsafe();
 
     static long alignDown(long value, long alignment) {
         return value & ~(alignment - 1);
--- a/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java	Wed Jul 05 22:32:06 2017 +0200
@@ -152,6 +152,9 @@
         try {
             ClassFileReader reader = ClassFileReader.newInstance(path);
             for (ClassFile cf : reader.getClassFiles()) {
+                if (cf.access_flags.is(AccessFlags.ACC_MODULE))
+                    continue;
+
                 String classFileName = cf.getName();
                 // for each ClassFile
                 //    parse constant pool to find matching method refs
--- a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java	Wed Jul 05 22:32:06 2017 +0200
@@ -50,15 +50,15 @@
     private static final String JAVA_COMPACT2 = "java.compact2";
 
     private static final ModuleDescriptor BASE
-        = new ModuleDescriptor.Builder(JAVA_BASE).build();
+        = ModuleDescriptor.module(JAVA_BASE).build();
 
     private static final ModuleDescriptor COMPACT2
-        = new ModuleDescriptor.Builder(JAVA_COMPACT2)
+        = ModuleDescriptor.module(JAVA_COMPACT2)
             .requires(Set.of(MANDATED), JAVA_BASE)
-            .requires(Set.of(PUBLIC), JAVA_COMPACT1)
-            .requires(Set.of(PUBLIC), "java.rmi")
-            .requires(Set.of(PUBLIC), "java.sql")
-            .requires(Set.of(PUBLIC), "java.xml")
+            .requires(Set.of(TRANSITIVE), JAVA_COMPACT1)
+            .requires(Set.of(TRANSITIVE), "java.rmi")
+            .requires(Set.of(TRANSITIVE), "java.sql")
+            .requires(Set.of(TRANSITIVE), "java.xml")
             .build();
 
     private static final Set<ModuleDescriptor> MREFS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/Basic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,317 @@
+/*
+ * 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
+ * @library modules
+ * @build m1/* m2/*
+ * @run testng/othervm --add-modules=m1,m2 Basic
+ * @summary Basic test of open modules and open packages
+ */
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InaccessibleObjectException;
+import java.lang.reflect.Module;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeTest;
+import static org.testng.Assert.*;
+
+/**
+ * open module m1 {
+ *     exports p;
+ *     // contains p.internal
+ * }
+ *
+ * module m2 {
+ *     exports q;
+ *     exports q;
+ *     // contains q.internal
+ * }
+ *
+ * Each package in m1 and m2 contains a public type a non-public type.
+ */
+
+public class Basic {
+
+    @BeforeTest
+    public void checkSetup() throws Exception {
+        Module m1 = Class.forName("p.PublicType").getModule();
+        assertTrue(m1.isNamed());
+        assertTrue(m1.getDescriptor().isOpen());
+        assertTrue(m1.getDescriptor().packages().size() == 2);
+        assertTrue(m1.getDescriptor().packages().contains("p"));
+        assertTrue(m1.getDescriptor().packages().contains("p.internal"));
+        assertTrue(m1.getDescriptor().exports().size() == 1);
+        ModuleDescriptor.Exports e = m1.getDescriptor().exports().iterator().next();
+        assertTrue(e.source().equals("p"));
+        assertTrue(m1.isOpen("p"));
+        assertTrue(m1.isOpen("p.internal"));
+
+        Module m2 = Class.forName("q.PublicType").getModule();
+        assertTrue(m2.isNamed());
+        assertFalse(m2.getDescriptor().isOpen());
+        assertTrue(m2.getDescriptor().packages().size() == 2);
+        assertTrue(m2.getDescriptor().packages().contains("q"));
+        assertTrue(m2.getDescriptor().packages().contains("q.internal"));
+        assertTrue(m2.getDescriptor().exports().size() == 1);
+        e = m2.getDescriptor().exports().iterator().next();
+        assertTrue(e.source().equals("q"));
+        assertTrue(m2.isOpen("q"));
+        assertFalse(m2.isOpen("p.internal"));
+    }
+
+    @Test
+    public void testPublicTypeInExportedPackage() throws Throwable {
+        // invokespecial
+        new p.PublicType();
+
+        Class<?> clazz = p.PublicType.class;
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        ctor.newInstance();
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testNotPublicTypeInExportedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("p.NotPublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testPublicTypeInNonExportedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("p.internal.PublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        ctor.newInstance(); // should succeed
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testNotPublicTypeInNonExportedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("p.internal.NotPublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testPublicTypeInOpenPackage() throws Throwable {
+        // invokespecial
+        // new q.PublicType();   TBD
+
+        // core reflection
+        Class<?> clazz = q.PublicType.class;
+        clazz.getConstructor().newInstance();
+
+        // method handles
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+
+    }
+
+    @Test
+    public void testNotPublicTypeInOpenPackage() throws Throwable {
+        Class<?> clazz = Class.forName("q.NotPublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testPublicTypeInConcealedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("q.internal.PublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            ctor.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+    }
+
+    @Test
+    public void testNotPublicTypeInConcealedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("q.internal.NotPublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            ctor.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+    }
+
+    /**
+     * Produces the method handle for the no-arg constructor and invokes it
+     */
+    Object findNoArgConstructorAndInvoke(Class<?> clazz, Lookup lookup) throws Throwable {
+        MethodType mt = MethodType.methodType(void.class);
+        MethodHandle mh = lookup.findConstructor(clazz, mt);
+        return mh.invoke();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+open module m1 {
+    exports p;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/p/NotPublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 p;
+
+class NotPublicType {
+    public NotPublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/p/PublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 p;
+
+public class PublicType {
+    public PublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/p/internal/NotPublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 p.internal;
+
+class NotPublicType {
+    public NotPublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/p/internal/PublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 p.internal;
+
+public class PublicType {
+    public PublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+module m2 {
+    exports q;
+    opens q;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/q/NotPublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 q;
+
+class NotPublicType {
+    public NotPublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/q/PublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 q;
+
+public class PublicType {
+    public PublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/q/internal/NotPublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 q.internal;
+
+class NotPublicType {
+    public NotPublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/q/internal/PublicType.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 q.internal;
+
+public class PublicType {
+    public PublicType() { }
+}
--- a/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -58,10 +58,10 @@
         assertTrue(requires.contains("java.base"));
 
         // uses ScriptEngineFactory
-        Map<String, Provides> provides = descriptor.provides();
+        Set<Provides> provides = descriptor.provides();
         assertTrue(provides.size() == 1);
         String sn = ScriptEngineFactory.class.getName();
-        assertTrue(provides.containsKey(sn));
+        assertTrue(provides.iterator().next().service().equals(sn));
 
         // Check that it is iterated over with ServiceLoader
         ServiceLoader<ScriptEngineFactory> sl
--- a/jdk/test/sun/net/idn/TestStringPrep.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/net/idn/TestStringPrep.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,8 @@
  * @test
  * @summary Unit test for sun.net.idn.Punycode
  * @bug 4737170 8060097
- * @modules java.base/sun.net.idn java.base/sun.text.normalizer
+ * @modules java.base/sun.net.idn:+open
+ *          java.base/sun.text.normalizer
  * @library .
  * @compile -XDignore.symbol.file TestStringPrep.java NFS4StringPrep.java
  *     TestData.java
--- a/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,7 @@
  * @summary HttpClient available() check throws SocketException when connection
  * has been closed
  * @modules java.base/sun.net
- *          java.base/sun.net.www.http
+ *          java.base/sun.net.www.http:+open
  */
 
 import java.net.URL;
--- a/jdk/test/sun/net/www/httptest/TestHttpServer.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/net/www/httptest/TestHttpServer.java	Wed Jul 05 22:32:06 2017 +0200
@@ -116,15 +116,26 @@
         }
     }
 
-    /** Tell all threads in the server to exit within 5 seconds.
-     *  This is an abortive termination. Just prior to the thread exiting
-     *  all channels in that thread waiting to be closed are forceably closed.
+    /**
+     * Tell all threads in the server to exit within 5 seconds.
+     * This is an abortive termination. Just prior to the thread exiting
+     * all channels in that thread waiting to be closed are forceably closed.
+     * @throws InterruptedException
      */
 
     public void terminate () {
         for (int i=0; i<threads; i++) {
             servers[i].terminate ();
         }
+
+        for (int i = 0; i < threads; i++) {
+            try {
+                servers[i].join();
+            } catch (InterruptedException e) {
+                System.err.println("Unexpected InterruptedException during terminating server");
+                throw new RuntimeException(e);
+            }
+        }
     }
 
     /**
@@ -147,7 +158,7 @@
         int maxconn;
         int nconn;
         ClosedChannelList clist;
-        boolean shutdown;
+        volatile boolean shutdown;
 
         Server (HttpCallback cb, ServerSocketChannel schan, int maxconn) {
             this.schan = schan;
@@ -166,18 +177,18 @@
         }
 
         /* Stop the thread as soon as possible */
-        public synchronized void terminate () {
+        public void terminate () {
             shutdown = true;
         }
 
         public void run ()  {
             try {
                 while (true) {
-                    selector.select (1000);
-                    Set selected = selector.selectedKeys();
-                    Iterator iter = selected.iterator();
+                    selector.select(1000);
+                    Set<SelectionKey> selected = selector.selectedKeys();
+                    Iterator<SelectionKey> iter = selected.iterator();
                     while (iter.hasNext()) {
-                        key = (SelectionKey)iter.next();
+                        key = iter.next();
                         if (key.equals (listenerKey)) {
                             SocketChannel sock = schan.accept ();
                             if (sock == null) {
@@ -200,7 +211,7 @@
                                 SocketChannel chan = (SocketChannel) key.channel();
                                 System.out.println("SERVER: connection readable. chan[" + chan + "]");
                                 if (key.attachment() != null) {
-                                    System.out.println("Server: comsume");
+                                    System.out.println("Server: consume");
                                     closed = consume (chan);
                                 } else {
                                     closed = read (chan, key);
@@ -219,7 +230,16 @@
                     }
                     clist.check();
                     if (shutdown) {
+                        System.out.println("Force to Shutdown");
+                        SelectionKey sKey = schan.keyFor(selector);
+                        if (sKey != null) {
+                            sKey.cancel();
+                        }
+
                         clist.terminate ();
+                        selector.close();
+                        schan.socket().close();
+                        schan.close();
                         return;
                     }
                 }
@@ -726,3 +746,4 @@
         }
     }
 }
+
--- a/jdk/test/sun/net/www/protocol/http/NoNTLM.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/net/www/protocol/http/NoNTLM.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @summary Sanity check that NTLM will not be selected by the http protocol
  *    handler when running on a profile that does not support NTLM
  * @modules java.base/sun.net.www
- *          java.base/sun.net.www.protocol.http
+ *          java.base/sun.net.www.protocol.http:open
  * @run main/othervm NoNTLM
  */
 
--- a/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8048194
  * @modules java.base/sun.security.util
  *          java.security.jgss/sun.security.jgss
- *          java.security.jgss/sun.security.jgss.spnego
+ *          java.security.jgss/sun.security.jgss.spnego:+open
  * @run main/othervm NotPreferredMech
  * @summary GSSContext.acceptSecContext fails when a supported mech is not initiator preferred
  */
--- a/jdk/test/sun/security/krb5/RFC396xTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/krb5/RFC396xTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @bug 6862679
  * @modules java.security.jgss/sun.security.krb5
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.crypto.dk
+ *          java.security.jgss/sun.security.krb5.internal.crypto.dk:+open
  * @run main/othervm RFC396xTest
  * @summary ESC: AD Authentication with user with umlauts fails
  */
--- a/jdk/test/sun/security/krb5/auto/Renew.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/krb5/auto/Renew.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,8 +27,8 @@
  * @summary JAAS Krb5LoginModule has suspect ticket-renewal logic,
  *          relies on clockskew grace
  * @modules java.base/sun.security.util
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
  *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
--- a/jdk/test/sun/security/krb5/auto/TEST.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/krb5/auto/TEST.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -1,8 +1,8 @@
 modules java.base/jdk.internal.misc \
         java.base/sun.security.util \
         java.security.jgss/sun.security.jgss \
-        java.security.jgss/sun.security.krb5 \
-        java.security.jgss/sun.security.krb5.internal \
+        java.security.jgss/sun.security.krb5:+open \
+        java.security.jgss/sun.security.krb5.internal:+open \
         java.security.jgss/sun.security.krb5.internal.ccache \
         java.security.jgss/sun.security.krb5.internal.rcache \
         java.security.jgss/sun.security.krb5.internal.crypto \
--- a/jdk/test/sun/security/krb5/ccache/TimeInCCache.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/krb5/ccache/TimeInCCache.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,7 @@
  * @test
  * @bug 6590930
  * @modules java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.ccache:+open
  * @run main/othervm TimeInCCache
  * @summary read/write does not match for ccache
  */
--- a/jdk/test/sun/security/krb5/config/DefUdpLimit.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/krb5/config/DefUdpLimit.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,8 +25,7 @@
  * @test
  * @bug 8009875
  * @summary Provide a default udp_preference_limit for krb5.conf
- * @modules java.security.jgss/sun.security.krb5
- * @compile -XDignore.symbol.file DefUdpLimit.java
+ * @modules java.security.jgss/sun.security.krb5:+open
  * @run main/othervm DefUdpLimit -1 1465
  * @run main/othervm DefUdpLimit 0 0
  * @run main/othervm DefUdpLimit 1234 1234
--- a/jdk/test/sun/security/krb5/config/DnsFallback.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/krb5/config/DnsFallback.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,7 +23,7 @@
 /*
  * @test
  * @bug 6673164 6552334 8077102
- * @modules java.security.jgss/sun.security.krb5
+ * @modules java.security.jgss/sun.security.krb5:+open
  * @run main/othervm DnsFallback
  * @summary fix dns_fallback parse error, and use dns by default
  */
--- a/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 7184246
  * @summary Simplify Config.get() of krb5
- * @modules java.security.jgss/sun.security.krb5
+ * @modules java.security.jgss/sun.security.krb5:+open
  */
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
--- a/jdk/test/sun/security/krb5/tools/KtabZero.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/krb5/tools/KtabZero.java	Wed Jul 05 22:32:06 2017 +0200
@@ -34,7 +34,7 @@
  * @bug 8014196
  * @summary ktab creates a file with zero kt_vno
  * @requires os.family == "windows"
- * @modules java.security.jgss/sun.security.krb5.internal.ktab
+ * @modules java.security.jgss/sun.security.krb5.internal.ktab:+open
  *          java.security.jgss/sun.security.krb5.internal.tools
  */
 public class KtabZero {
--- a/jdk/test/sun/security/pkcs11/PKCS11Test.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/pkcs11/PKCS11Test.java	Wed Jul 05 22:32:06 2017 +0200
@@ -642,6 +642,8 @@
     static final boolean badNSSVersion =
             getNSSVersion() >= 3.11 && getNSSVersion() < 3.12;
 
+    private static final String distro = distro();
+
     static final boolean badSolarisSparc =
             System.getProperty("os.name").equals("SunOS") &&
             System.getProperty("os.arch").equals("sparcv9") &&
@@ -735,13 +737,17 @@
      * Get the identifier for the operating system distribution
      */
     static String getDistro() {
+        return distro;
+    }
+
+    private static String distro() {
         try (BufferedReader in =
             new BufferedReader(new InputStreamReader(
                 Runtime.getRuntime().exec("uname -v").getInputStream()))) {
 
             return in.readLine();
         } catch (Exception e) {
-            return "";
+            throw new RuntimeException("Failed to determine distro.", e);
         }
     }
 
--- a/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -24,7 +24,8 @@
 /**
  * @test
  * @bug 8047769
- * @modules java.base/sun.security.provider
+ * @modules java.base/java.lang.ref:open
+ *          java.base/sun.security.provider:open
  * @summary SecureRandom should be more frugal with file descriptors
  */
 
--- a/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java	Wed Jul 05 22:32:06 2017 +0200
@@ -33,7 +33,8 @@
 /**
  * @test
  * @bug 8051408
- * @modules java.base/sun.security.provider
+ * @modules java.base/java.lang.reflect:open
+ *          java.base/sun.security.provider:+open
  * @run main/othervm CommonSeeder
  * @summary check entropy reading of DRBGs
  */
--- a/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,7 +32,7 @@
 /**
  * @test
  * @bug 8157308
- * @modules java.base/sun.security.provider
+ * @modules java.base/sun.security.provider:+open
  * @summary Make AbstractDrbg non-Serializable
  * @run main DRBGS11n mech
  * @run main DRBGS11n capability
--- a/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,8 @@
  * @bug 8080535
  * @summary Expected size of Character.UnicodeBlock.map is not optimal
  * @library /lib/testlibrary
- * @modules java.base/sun.security.ssl
+ * @modules java.base/java.util:open
+ *          java.base/sun.security.ssl:open
  * @build jdk.testlibrary.OptimalCapacity
  * @run main OptimalListSize
  */
--- a/jdk/test/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -28,9 +28,12 @@
 
 /*
  * @test
- * @bug 6916074
+ * @bug 6916074 8170131
  * @summary Add support for TLS 1.2
- * @run main/othervm PKIXExtendedTM
+ * @run main/othervm PKIXExtendedTM 0
+ * @run main/othervm PKIXExtendedTM 1
+ * @run main/othervm PKIXExtendedTM 2
+ * @run main/othervm PKIXExtendedTM 3
  */
 
 import java.net.*;
@@ -42,6 +45,7 @@
 import java.security.KeyFactory;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
+import java.security.cert.CertPathValidatorException;
 import java.security.spec.*;
 import java.security.interfaces.*;
 import java.math.BigInteger;
@@ -792,20 +796,85 @@
     volatile Exception serverException = null;
     volatile Exception clientException = null;
 
+    static class Test {
+        String tlsDisAlgs;
+        String certPathDisAlgs;
+        boolean fail;
+        Test(String tlsDisAlgs, String certPathDisAlgs, boolean fail) {
+            this.tlsDisAlgs = tlsDisAlgs;
+            this.certPathDisAlgs = certPathDisAlgs;
+            this.fail = fail;
+        }
+    }
+
+    static Test[] tests = {
+        // MD5 is used in this test case, don't disable MD5 algorithm.
+        new Test(
+            "SSLv3, RC4, DH keySize < 768",
+            "MD2, RSA keySize < 1024",
+            false),
+        // Disable MD5 but only if cert chains back to public root CA, should
+        // pass because the MD5 cert in this test case is issued by test CA
+        new Test(
+            "SSLv3, RC4, DH keySize < 768",
+            "MD2, MD5 jdkCA, RSA keySize < 1024",
+            false),
+        // Disable MD5 alg via TLS property and expect failure
+        new Test(
+            "SSLv3, MD5, RC4, DH keySize < 768",
+            "MD2, RSA keySize < 1024",
+            true),
+        // Disable MD5 alg via certpath property and expect failure
+        new Test(
+            "SSLv3, RC4, DH keySize < 768",
+            "MD2, MD5, RSA keySize < 1024",
+            true),
+    };
+
     public static void main(String args[]) throws Exception {
-        // MD5 is used in this test case, don't disable MD5 algorithm.
+        if (args.length != 1) {
+            throw new Exception("Incorrect number of arguments");
+        }
+        Test test = tests[Integer.parseInt(args[0])];
+        Security.setProperty("jdk.tls.disabledAlgorithms", test.tlsDisAlgs);
         Security.setProperty("jdk.certpath.disabledAlgorithms",
-                "MD2, RSA keySize < 1024");
-        Security.setProperty("jdk.tls.disabledAlgorithms",
-                "SSLv3, RC4, DH keySize < 768");
+                             test.certPathDisAlgs);
 
-        if (debug)
+        if (debug) {
             System.setProperty("javax.net.debug", "all");
+        }
 
         /*
          * Start the tests.
          */
-        new PKIXExtendedTM();
+        try {
+            new PKIXExtendedTM();
+            if (test.fail) {
+                throw new Exception("Expected MD5 certificate to be blocked");
+            }
+        } catch (Exception e) {
+            if (test.fail) {
+                // find expected cause
+                boolean correctReason = false;
+                Throwable cause = e.getCause();
+                while (cause != null) {
+                    if (cause instanceof CertPathValidatorException) {
+                        CertPathValidatorException cpve =
+                            (CertPathValidatorException)cause;
+                        if (cpve.getReason() == CertPathValidatorException.BasicReason.ALGORITHM_CONSTRAINED) {
+                            correctReason = true;
+                            break;
+                        }
+                    }
+                    cause = cause.getCause();
+                }
+                if (!correctReason) {
+                    throw new Exception("Unexpected exception", e);
+                }
+            } else {
+                throw e;
+            }
+        }
     }
 
     Thread clientThread = null;
--- a/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,7 +27,7 @@
  * @summary Make sure jar files with large entries (more than max heap size)
  *    can be signed
  * @modules jdk.jartool/sun.security.tools.jarsigner
- * @run main/othervm -Xmx8M LargeJarEntry
+ * @run main/othervm -Xmx16m LargeJarEntry
  * @author Sean Mullan
  */
 
--- a/jdk/test/sun/security/tools/keytool/StartDateTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/tools/keytool/StartDateTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,8 +25,7 @@
  * @test
  * @bug 6468285
  * @summary keytool ability to backdate self-signed certificates to compensate for clock skew
- * @modules java.base/sun.security.tools.keytool
- * @compile -XDignore.symbol.file StartDateTest.java
+ * @modules java.base/sun.security.tools.keytool:+open
  * @run main StartDateTest
  */
 
--- a/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @author Gary Ellison
  * @bug 4170635
  * @summary Verify equals()/hashCode() contract honored
- * @modules java.base/sun.security.util
+ * @modules java.base/sun.security.util:+open
  *          java.base/sun.security.x509
  * @run main/othervm/policy=Allow.policy DerInputBufferEqualsHashCode
  */
--- a/jdk/test/sun/text/resources/LocaleData	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/text/resources/LocaleData	Wed Jul 05 22:32:06 2017 +0200
@@ -8293,3 +8293,9 @@
 # bug #8145952
 CurrencyNames//byn=Belarusian Ruble
 CurrencyNames/be_BY/BYN=\u0420\u0443\u0431
+
+# bug #8037111
+FormatData/sv/NumberPatterns/2=#,##0 %
+# bug #8081643
+FormatData/sr-Latin/NumberElements/0=,
+FormatData/sr-Latin/NumberElements/1=.
--- a/jdk/test/sun/text/resources/LocaleDataTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/text/resources/LocaleDataTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -37,7 +37,7 @@
  *      7003124 7085757 7028073 7171028 7189611 8000983 7195759 8004489 8006509
  *      7114053 7074882 7040556 8008577 8013836 8021121 6192407 6931564 8027695
  *      8017142 8037343 8055222 8042126 8074791 8075173 8080774 8129361 8134916
- *      8145136 8145952 8164784
+ *      8145136 8145952 8164784 8037111 8081643
  * @summary Verify locale data
  * @modules java.base/sun.util.resources
  * @modules jdk.localedata
--- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -27,6 +27,7 @@
  *  @bug 5008856 5023573 5024917 5062569 7172176
  *  @summary 'missing resource key' error for key = "Operating system"
  *  @modules jdk.jconsole/sun.tools.jconsole
+ *           jdk.jconsole/sun.tools.jconsole.resources:open
  *  @run main ResourceCheckTest
  */
 
--- a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8007572 8008161 8157792
  * @summary Test whether the TimeZone generated from JSR310 tzdb is the same
  * as the one from the tz data from javazic
- * @modules java.base/sun.util.calendar
+ * @modules java.base/sun.util.calendar:+open
  * @build BackEnd Checksum DayOfWeek Gen GenDoc Main Mappings Month
  *        Rule RuleDay RuleRec Simple TestZoneInfo310 Time Timezone
  *        TzIDOldMapping Zone ZoneInfoFile ZoneInfoOld ZoneRec Zoneinfo
--- a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jar/mmrjar/ConcealedPackage.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,8 @@
  * @bug 8146486
  * @summary Fail to create a MR modular JAR with a versioned entry in
  *          base-versioned empty package
+ * @modules jdk.compiler
+ *          jdk.jartool
  * @library /lib/testlibrary
  * @build jdk.testlibrary.FileUtils
  * @run testng ConcealedPackage
@@ -56,6 +58,7 @@
     private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac")
             .orElseThrow(() -> new RuntimeException("javac tool not found"));
     private final String linesep = System.lineSeparator();
+    private final Path testsrc;
     private final Path userdir;
     private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream();
     private final PrintStream out = new PrintStream(outbytes, true);
@@ -63,7 +66,7 @@
     private final PrintStream err = new PrintStream(errbytes, true);
 
     public ConcealedPackage() throws IOException {
-        Path testsrc = Paths.get(System.getProperty("test.src"));
+        testsrc = Paths.get(System.getProperty("test.src"));
         userdir = Paths.get(System.getProperty("user.dir", "."));
 
         // compile the classes directory
@@ -124,8 +127,7 @@
 
         jar("-tf mmr.jar");
 
-        String s = new String(outbytes.toByteArray());
-        Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
+        Set<String> actual = lines(outbytes);
         Set<String> expected = Set.of(
                 "META-INF/",
                 "META-INF/MANIFEST.MF",
@@ -139,10 +141,8 @@
         rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class");
         Assert.assertEquals(rc, 1);
 
-        s = new String(errbytes.toByteArray());
-        Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public "
-                + "class not found in base entries")
-        );
+        String s = new String(errbytes.toByteArray());
+        Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
     }
 
     // updates a valid multi-release jar with a module-info class and new
@@ -158,15 +158,11 @@
         Assert.assertEquals(rc, 0);
 
         String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a "
-                        + "concealed package, \nplacing this jar on the class path "
-                        + "will result in incompatible public interfaces")
-        );
+        Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
 
         jar("-tf mmr.jar");
 
-        s = new String(outbytes.toByteArray());
-        Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
+        Set<String> actual = lines(outbytes);
         Set<String> expected = Set.of(
                 "META-INF/",
                 "META-INF/MANIFEST.MF",
@@ -186,9 +182,7 @@
         Assert.assertEquals(rc, 1);
 
         String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public "
-                + "class not found in base entries")
-        );
+        Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
     }
 
     // jar tool succeeds building mmr.jar because of concealed package
@@ -199,15 +193,11 @@
         Assert.assertEquals(rc, 0);
 
         String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a "
-                + "concealed package, \nplacing this jar on the class path "
-                + "will result in incompatible public interfaces")
-        );
+        Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
 
         jar("-tf mmr.jar");
 
-        s = new String(outbytes.toByteArray());
-        Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
+        Set<String> actual = lines(outbytes);
         Set<String> expected = Set.of(
                 "META-INF/",
                 "META-INF/MANIFEST.MF",
@@ -222,4 +212,128 @@
         );
         Assert.assertEquals(actual, expected);
     }
+
+    // jar tool does two updates, no exported packages, all concealed
+    @Test
+    public void test5() throws IOException {
+        // compile the mr10 directory
+        Path source = testsrc.resolve("src").resolve("mr10");
+        Path destination = Paths.get("mr10");
+        javac(source, destination);
+
+        // create a directory for this tests special files
+        Files.createDirectory(Paths.get("test5"));
+
+        // create an empty module-info.java
+        String hi = "module hi {" + linesep + "}" + linesep;
+        Path modinfo = Paths.get("test5", "module-info.java");
+        Files.write(modinfo, hi.getBytes());
+
+        // and compile it
+        javac(modinfo, Paths.get("test5"));
+
+        int rc = jar("--create --file mr.jar -C classes .");
+        Assert.assertEquals(rc, 0);
+
+        rc = jar("--update --file mr.jar -C test5 module-info.class"
+                + " --release 9 -C mr9 .");
+        Assert.assertEquals(rc, 0);
+
+        jar("tf mr.jar");
+
+        Set<String> actual = lines(outbytes);
+        Set<String> expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/p/",
+                "META-INF/versions/9/p/Hi.class",
+                "META-INF/versions/9/p/internal/",
+                "META-INF/versions/9/p/internal/Bar.class",
+                "module-info.class"
+        );
+        Assert.assertEquals(actual, expected);
+
+        jar("-d --file mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "hi",
+                "requires mandated java.base",
+                "contains p",
+                "contains p.internal"
+        );
+        Assert.assertEquals(actual, expected);
+
+        rc = jar("--update --file mr.jar --release 10 -C mr10 .");
+        Assert.assertEquals(rc, 0);
+
+        jar("tf mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/p/",
+                "META-INF/versions/9/p/Hi.class",
+                "META-INF/versions/9/p/internal/",
+                "META-INF/versions/9/p/internal/Bar.class",
+                "META-INF/versions/10/p/",
+                "META-INF/versions/10/p/internal/",
+                "META-INF/versions/10/p/internal/bar/",
+                "META-INF/versions/10/p/internal/bar/Gee.class",
+                "module-info.class"
+        );
+        Assert.assertEquals(actual, expected);
+
+        jar("-d --file mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "hi",
+                "requires mandated java.base",
+                "contains p",
+                "contains p.internal",
+                "contains p.internal.bar"
+        );
+        Assert.assertEquals(actual, expected);
+    }
+
+    private static Set<String> lines(ByteArrayOutputStream baos) {
+        String s = new String(baos.toByteArray());
+        return Arrays.stream(s.split("\\R"))
+                     .map(l -> l.trim())
+                     .filter(l -> l.length() > 0)
+                     .collect(Collectors.toSet());
+    }
+
+    static enum Message {
+        NOT_FOUND_IN_BASE_ENTRY(
+          ", contains a new public class not found in base entries"
+        ),
+        NEW_CONCEALED_PACKAGE_WARNING(
+            " is a public class" +
+            " in a concealed package, placing this jar on the class path will result" +
+            " in incompatible public interfaces"
+        );
+
+        final String msg;
+        Message(String msg) {
+            this.msg = msg;
+        }
+
+        /*
+         * Test if the given output contains this message ignoring the line break.
+         */
+        boolean match(String output, String entry) {
+            System.out.println("Expected: " + entry + msg);
+            System.out.println("Found: " + output);
+            return Arrays.stream(output.split("\\R"))
+                         .collect(Collectors.joining(" "))
+                         .contains(entry + msg);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/mmrjar/src/mr10/p/internal/bar/Gee.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,7 @@
+package p.internal.bar;
+
+public class Gee {
+    public void geeWhiz() {
+        System.out.println("Gee whiz");
+    }
+}
--- a/jdk/test/tools/jar/modularJar/Basic.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jar/modularJar/Basic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,19 +22,18 @@
  */
 
 import java.io.*;
+import java.lang.module.ModuleDescriptor;
 import java.lang.reflect.Method;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
+import java.nio.file.*;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.*;
 import java.util.function.Consumer;
 import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
 import java.util.jar.JarInputStream;
 import java.util.jar.Manifest;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import jdk.testlibrary.FileUtils;
@@ -47,6 +46,7 @@
 
 /*
  * @test
+ * @bug 8167328
  * @library /lib/testlibrary
  * @modules jdk.compiler
  *          jdk.jartool
@@ -76,7 +76,8 @@
                                                    Set.of("jdk.test.foo"),
                                                    null, // no uses
                                                    null, // no provides
-                                                   Set.of("jdk.test.foo.internal"));
+                                                   Set.of("jdk.test.foo.internal",
+                                                          "jdk.test.foo.resources"));
     static TestModuleData BAR = new TestModuleData("bar",
                                                    "4.5.6.7",
                                                    "jdk.test.bar.Bar",
@@ -99,17 +100,18 @@
         final String version;
         final String message;
         final String hashes;
-        final Set<String> conceals;
+        final Set<String> packages;
 
         TestModuleData(String mn, String v, String mc, String m, String h,
                        Set<String> requires, Set<String> exports, Set<String> uses,
-                       Set<String> provides, Set<String> conceals) {
+                       Set<String> provides, Set<String> contains) {
             moduleName = mn; mainClass = mc; version = v; message = m; hashes = h;
-            this.requires = requires;
-            this.exports = exports;
-            this.uses = uses;
-            this.provides = provides;
-            this.conceals = conceals;
+            this.requires = requires != null ? requires : Collections.emptySet();
+            this.exports = exports != null ? exports : Collections.emptySet();
+            this.uses = uses != null ? uses : Collections.emptySet();;
+            this.provides = provides != null ? provides : Collections.emptySet();
+            this.packages = Stream.concat(this.exports.stream(), contains.stream())
+                                  .collect(Collectors.toSet());
         }
         static TestModuleData from(String s) {
             try {
@@ -148,8 +150,8 @@
                         provides = stringToSet(line);
                     } else if (line.startsWith("hashes:")) {
                         hashes = line.substring("hashes:".length());
-                    } else if (line.startsWith("conceals:")) {
-                        line = line.substring("conceals:".length());
+                    } else if (line.startsWith("contains:")) {
+                        line = line.substring("contains:".length());
                         conceals = stringToSet(line);
                     } else {
                         throw new AssertionError("Unknown value " + line);
@@ -192,16 +194,14 @@
         assertSetsEqual(expected.exports, received.exports);
         assertSetsEqual(expected.uses, received.uses);
         assertSetsEqual(expected.provides, received.provides);
-        assertSetsEqual(expected.conceals, received.conceals);
+        assertSetsEqual(expected.packages, received.packages);
     }
 
     static void assertSetsEqual(Set<String> s1, Set<String> s2) {
-        if (s1 == null && s2 == null) // none expected, or received
-            return;
-        assertTrue(s1.size() == s2.size(),
-                   "Unexpected set size difference: ", s1.size(), ", ", s2.size());
-        s1.forEach(p -> assertTrue(s2.contains(p), "Expected ", p, ", in ", s2));
-    }
+        if (!s1.equals(s2)) {
+            org.testng.Assert.assertTrue(false, s1 + " vs " + s2);
+        }
+     }
 
     @BeforeTest
     public void compileModules() throws Exception {
@@ -209,6 +209,11 @@
         compileModule(BAR.moduleName, MODULE_CLASSES);
         compileModule("baz");  // for service provider consistency checking
 
+        // copy resources
+        copyResource(TEST_SRC.resolve("src").resolve(FOO.moduleName),
+                     MODULE_CLASSES.resolve(FOO.moduleName),
+                     "jdk/test/foo/resources/foo.properties");
+
         setupMRJARModuleInfo(FOO.moduleName);
         setupMRJARModuleInfo(BAR.moduleName);
         setupMRJARModuleInfo("baz");
@@ -228,6 +233,12 @@
             "--no-manifest",
             "-C", modClasses.toString(), ".")
             .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo",
+                               "jdk.test.foo.resources",
+                               "jdk.test.foo.internal"));
+
         java(mp, FOO.moduleName + "/" + FOO.mainClass)
             .assertSuccess()
             .resultChecker(r -> assertModuleData(r, FOO));
@@ -375,7 +386,8 @@
             "--file=" + modularJar.toString(),
             "--no-manifest",
             "-C", modClasses.toString(), "module-info.class",
-            "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
+            "-C", modClasses.toString(), "jdk/test/foo/Foo.class",
+            "-C", modClasses.toString(), "jdk/test/foo/resources/foo.properties")
             .assertSuccess();
         jar("--update",
             "--file=" + modularJar.toString(),
@@ -471,13 +483,63 @@
                            "Expecting to find \"bar, requires foo,...\"",
                            "in output, but did not: [" + r.output + "]");
                 p = Pattern.compile(
-                        "conceals\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal");
+                        "contains\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal");
                 assertTrue(p.matcher(r.output).find(),
-                           "Expecting to find \"conceals jdk.test.foo,...\"",
+                           "Expecting to find \"contains jdk.test.foo,...\"",
                            "in output, but did not: [" + r.output + "]");
             });
     }
 
+
+    @Test
+    public void partialUpdateFooPackagesAttribute() throws IOException {
+        Path mp = Paths.get("partialUpdateFooPackagesAttribute");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        // Not all files, and none from non-exported packages,
+        // i.e. no concealed list in first create
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--no-manifest",
+            "-C", modClasses.toString(), "module-info.class",
+            "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo"));
+
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "jdk/test/foo/resources/foo.properties")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo", "jdk.test.foo.resources"));
+
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), "jdk/test/foo/internal/Message.class")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo",
+                               "jdk.test.foo.resources",
+                               "jdk.test.foo.internal"));
+
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+    }
+
+    private Set<String> readPackagesAttribute(Path jar) {
+        return getModuleDescriptor(jar).packages();
+    }
+
     @Test
     public void hashBarInFooModule() throws IOException {
         Path mp = Paths.get("dependencesFooBar");
@@ -506,6 +568,7 @@
             .assertSuccess();
 
         java(mp, BAR.moduleName + "/" + BAR.mainClass,
+             "--add-exports", "java.base/jdk.internal.misc=bar",
              "--add-exports", "java.base/jdk.internal.module=bar")
             .assertSuccess()
             .resultChecker(r -> {
@@ -550,6 +613,7 @@
             "-C", barClasses.toString(), ".").assertSuccess();
 
         java(mp, BAR.moduleName + "/" + BAR.mainClass,
+             "--add-exports", "java.base/jdk.internal.misc=bar",
              "--add-exports", "java.base/jdk.internal.module=bar")
             .assertFailure()
             .resultChecker(r -> {
@@ -693,6 +757,14 @@
                                "Expected to find ", FOO.moduleName + "@" + FOO.version,
                                " in [", r.output, "]")
                 );
+
+            jar(option,
+                "--file=" + modularJar.toString(),
+                modularJar.toString())
+            .assertFailure();
+
+            jar(option, modularJar.toString())
+            .assertFailure();
         }
     }
 
@@ -750,12 +822,22 @@
     static Path compileModule(String mn, Path mp)
         throws IOException
     {
-        Path fooSourcePath = TEST_SRC.resolve("src").resolve(mn);
+        Path sourcePath = TEST_SRC.resolve("src").resolve(mn);
         Path build = Files.createDirectories(MODULE_CLASSES.resolve(mn));
-        javac(build, mp, fileList(fooSourcePath));
+        javac(build, mp, sourceList(sourcePath));
         return build;
     }
 
+    static void copyResource(Path srcDir, Path dir, String resource)
+        throws IOException
+    {
+        Path dest = dir.resolve(resource);
+        Files.deleteIfExists(dest);
+
+        Files.createDirectories(dest.getParent());
+        Files.copy(srcDir.resolve(resource), dest);
+    }
+
     static void setupMRJARModuleInfo(String moduleName) throws IOException {
         Path modClasses = MODULE_CLASSES.resolve(moduleName);
         Path metaInfDir = MRJAR_DIR.resolve(moduleName).resolve("META-INF");
@@ -774,6 +856,18 @@
         }
     }
 
+    static ModuleDescriptor getModuleDescriptor(Path jar) {
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        try (JarFile jf = new JarFile(jar.toFile())) {
+            JarEntry entry = jf.getJarEntry("module-info.class");
+            try (InputStream in = jf.getInputStream(entry)) {
+                return ModuleDescriptor.read(in);
+            }
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
     // Re-enable when there is support in javax.tools for module path
 //    static void javac(Path dest, Path... sourceFiles) throws IOException {
 //        out.printf("Compiling %d source files %s%n", sourceFiles.length,
@@ -817,6 +911,8 @@
         commands.add(dest.toString());
         if (dest.toString().contains("bar")) {
             commands.add("--add-exports");
+            commands.add("java.base/jdk.internal.misc=bar");
+            commands.add("--add-exports");
             commands.add("java.base/jdk.internal.module=bar");
         }
         if (modulePath != null) {
@@ -848,17 +944,10 @@
         return run(new ProcessBuilder(commands));
     }
 
-    static Path[] fileList(Path directory) throws IOException {
-        final List<Path> filePaths = new ArrayList<>();
-        Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
-            @Override
-            public FileVisitResult visitFile(Path file,
-                                             BasicFileAttributes attrs) {
-                filePaths.add(file);
-                return FileVisitResult.CONTINUE;
-            }
-        });
-        return filePaths.toArray(new Path[filePaths.size()]);
+    static Path[] sourceList(Path directory) throws IOException {
+        return Files.find(directory, Integer.MAX_VALUE,
+                          (file, attrs) -> (file.toString().endsWith(".java")))
+                    .toArray(Path[]::new);
     }
 
     static void createTestDir(Path p) throws IOException{
--- a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,10 +26,14 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.reflect.Method;
+import java.lang.module.ModuleDescriptor.Provides;
 import java.util.Optional;
 import java.util.StringJoiner;
+import java.util.HashSet;
+import java.util.Set;
 
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.module.ModuleHashes;
 import jdk.test.bar.internal.Message;
 
@@ -56,19 +60,20 @@
             System.out.println("uses:" + sj.toString());
 
         sj = new StringJoiner(",");
-        md.provides().keySet().stream().sorted().forEach(sj::add);
+        md.provides().stream().map(Provides::service).sorted().forEach(sj::add);
         if (!sj.toString().equals(""))
             System.out.println("provides:" + sj.toString());
 
         sj = new StringJoiner(",");
-        md.conceals().forEach(sj::add);
+        Set<String> concealed = new HashSet<>(md.packages());
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        concealed.forEach(sj::add);
         if (!sj.toString().equals(""))
-            System.out.println("conceals:" + sj.toString());
+            System.out.println("contains:" + sj.toString());
 
-        Method m = ModuleDescriptor.class.getDeclaredMethod("hashes");
-        m.setAccessible(true);
         ModuleDescriptor foo = jdk.test.foo.Foo.class.getModule().getDescriptor();
-        Optional<ModuleHashes> oHashes = (Optional<ModuleHashes>) m.invoke(foo);
+        JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess();
+        Optional<ModuleHashes> oHashes = jlma.hashes(foo);
         System.out.println("hashes:" + oHashes.get().hashFor("bar"));
     }
 }
--- a/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,7 +26,10 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Provides;
 import java.util.StringJoiner;
+import java.util.HashSet;
+import java.util.Set;
 
 import jdk.test.foo.internal.Message;
 
@@ -53,13 +56,15 @@
             System.out.println("uses:" + sj.toString());
 
         sj = new StringJoiner(",");
-        md.provides().keySet().stream().sorted().forEach(sj::add);
+        md.provides().stream().map(Provides::service).sorted().forEach(sj::add);
         if (!sj.toString().equals(""))
             System.out.println("provides:" + sj.toString());
 
         sj = new StringJoiner(",");
-        md.conceals().forEach(sj::add);
+        Set<String> concealed = new HashSet<>(md.packages());
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        concealed.forEach(sj::add);
         if (!sj.toString().equals(""))
-            System.out.println("conceals:" + sj.toString());
+            System.out.println("contains:" + sj.toString());
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/resources/foo.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,1 @@
+name = foo
--- a/jdk/test/tools/jar/multiRelease/Basic.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jar/multiRelease/Basic.java	Wed Jul 05 22:32:06 2017 +0200
@@ -25,7 +25,9 @@
  * @test
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
- * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Platform
+ *          jdk.compiler
+ *          jdk.jartool
+ * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils
  * @run testng Basic
  */
 
@@ -39,12 +41,14 @@
 import java.util.*;
 import java.util.function.Consumer;
 import java.util.jar.*;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.zip.*;
 
 import jdk.test.lib.JDKToolFinder;
 import jdk.test.lib.Utils;
 
+
 import static java.lang.String.format;
 import static java.lang.System.out;
 
@@ -292,7 +296,7 @@
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
                 .assertSuccess()
                 .resultChecker(r ->
-                        assertTrue(r.output.contains("contains a class that is identical"), r.output)
+                        assertTrue(r.outputContains("contains a class that is identical"), r.output)
                 );
 
         delete(jarfile);
@@ -450,7 +454,7 @@
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
                 .assertFailure()
                 .resultChecker(r ->
-                        assertTrue(r.output.contains("an isolated nested class"), r.output)
+                        assertTrue(r.outputContains("an isolated nested class"), r.output)
                 );
 
         delete(jarfile);
@@ -605,6 +609,13 @@
             this.ec = ec;
             this.output = output;
         }
+
+        boolean outputContains(String msg) {
+            return Arrays.stream(output.split("\\R"))
+                         .collect(Collectors.joining(" "))
+                         .contains(msg);
+        }
+
         Result assertSuccess() {
             assertTrue(ec == 0, format("ec: %d, output: %s", ec, output));
             return this;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/multiRelease/Basic1.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,245 @@
+/*
+ * 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
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          jdk.compiler
+ *          jdk.jartool
+ * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils
+ * @run testng Basic1
+ */
+
+import static org.testng.Assert.*;
+
+import org.testng.annotations.*;
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.jar.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.*;
+
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.Utils;
+
+
+import static java.lang.String.format;
+import static java.lang.System.out;
+
+public class Basic1 {
+    private final String src = System.getProperty("test.src", ".");
+
+    @BeforeTest
+    public void setup() throws IOException {
+        String test = "test01";
+        Path classes = Paths.get("classes", "base");
+        Files.createDirectories(classes);
+        Path source = Paths.get(src, "data", test, "base", "version");
+        javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
+
+        Path v9 = Paths.get("v9").resolve("META-INF").resolve("versions").resolve("9");
+        Files.createDirectories(v9);
+        source = Paths.get(src, "data", test, "v9", "version");
+        javac(v9, source.resolve("Version.java"));
+
+        Path v10 = Paths.get("v10").resolve("META-INF").resolve("versions").resolve("10");
+        Files.createDirectories(v10);
+        source = Paths.get(src, "data", test, "v10", "version");
+        javac(v10, source.resolve("Version.java"));
+    }
+
+    @Test
+    public void test() throws IOException {
+        String jarfile = "test.jar";
+        Path classes = Paths.get("classes");
+        Path v9 = Paths.get("v9");
+        Path v10 = Paths.get("v10");
+
+        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+            "--release", "9", "-C", v9.toString(), ".",
+            "--release", "10", "-C", v10.toString(), ".")
+            .assertSuccess();
+
+        checkMultiRelease(jarfile, true);
+
+        Map<String,String[]> names = Map.of(
+            "version/Main.class",
+            new String[] {"classes", "base", "version", "Main.class"},
+
+            "version/Version.class",
+            new String[] {"classes", "base", "version", "Version.class"},
+
+            "META-INF/versions/9/version/Version.class",
+            new String[] {"v9", "META-INF", "versions", "9", "version", "Version.class"},
+
+            "META-INF/versions/10/version/Version.class",
+            new String[] {"v10", "META-INF", "versions", "10", "version", "Version.class"}
+        );
+
+        compare(jarfile, names);
+    }
+
+    @Test
+    public void testFail() throws IOException {
+        String jarfile = "test.jar";
+        Path classes = Paths.get("classes");
+        Path v9 = Paths.get("v9");
+        Path v10 = Paths.get("v10");
+
+        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+            "--release", "9", "-C", v10.toString(), ".")
+            .assertFailure()
+            .outputContains("unexpected versioned entry META-INF/versions/");
+    }
+
+    private void checkMultiRelease(String jarFile, boolean expected) throws IOException {
+        try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ,
+                JarFile.runtimeVersion())) {
+            assertEquals(jf.isMultiRelease(), expected);
+        }
+    }
+
+    // compares the bytes found in the jar entries with the bytes found in the
+    // corresponding data files used to create the entries
+    private void compare(String jarfile, Map<String,String[]> names) throws IOException {
+        try (JarFile jf = new JarFile(jarfile)) {
+            for (String name : names.keySet()) {
+                Path path = Paths.get("", names.get(name));
+                byte[] b1 = Files.readAllBytes(path);
+                byte[] b2;
+                JarEntry je = jf.getJarEntry(name);
+                try (InputStream is = jf.getInputStream(je)) {
+                    b2 = is.readAllBytes();
+                }
+                assertEquals(b1,b2);
+            }
+        }
+    }
+
+    /*
+     * The following methods were taken from modular jar and other jar tests
+     */
+
+    void javac(Path dest, Path... sourceFiles) throws IOException {
+        String javac = JDKToolFinder.getJDKTool("javac");
+
+        List<String> commands = new ArrayList<>();
+        commands.add(javac);
+        String opts = System.getProperty("test.compiler.opts");
+        if (!opts.isEmpty()) {
+            commands.addAll(Arrays.asList(opts.split(" +")));
+        }
+        commands.add("-d");
+        commands.add(dest.toString());
+        Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x));
+
+        quickFail(run(new ProcessBuilder(commands)));
+    }
+
+    Result jarWithStdin(File stdinSource, String... args) {
+        String jar = JDKToolFinder.getJDKTool("jar");
+        List<String> commands = new ArrayList<>();
+        commands.add(jar);
+        commands.addAll(Utils.getForwardVmOptions());
+        Stream.of(args).forEach(x -> commands.add(x));
+        ProcessBuilder p = new ProcessBuilder(commands);
+        if (stdinSource != null)
+            p.redirectInput(stdinSource);
+        return run(p);
+    }
+
+    Result jar(String... args) {
+        return jarWithStdin(null, args);
+    }
+
+    void quickFail(Result r) {
+        if (r.ec != 0)
+            throw new RuntimeException(r.output);
+    }
+
+    Result run(ProcessBuilder pb) {
+        Process p;
+        out.printf("Running: %s%n", pb.command());
+        try {
+            p = pb.start();
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    format("Couldn't start process '%s'", pb.command()), e);
+        }
+
+        String output;
+        try {
+            output = toString(p.getInputStream(), p.getErrorStream());
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    format("Couldn't read process output '%s'", pb.command()), e);
+        }
+
+        try {
+            p.waitFor();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(
+                    format("Process hasn't finished '%s'", pb.command()), e);
+        }
+        return new Result(p.exitValue(), output);
+    }
+
+    String toString(InputStream in1, InputStream in2) throws IOException {
+        try (ByteArrayOutputStream dst = new ByteArrayOutputStream();
+             InputStream concatenated = new SequenceInputStream(in1, in2)) {
+            concatenated.transferTo(dst);
+            return new String(dst.toByteArray(), "UTF-8");
+        }
+    }
+
+    static class Result {
+        final int ec;
+        final String output;
+
+        private Result(int ec, String output) {
+            this.ec = ec;
+            this.output = output;
+        }
+
+        boolean outputContains(String msg) {
+            return Arrays.stream(output.split("\\R"))
+                         .collect(Collectors.joining(" "))
+                         .contains(msg);
+        }
+
+        Result assertSuccess() {
+            assertTrue(ec == 0, format("ec: %d, output: %s", ec, output));
+            return this;
+        }
+        Result assertFailure() {
+            assertTrue(ec != 0, format("ec: %d, output: %s", ec, output));
+            return this;
+        }
+        Result resultChecker(Consumer<Result> r) { r.accept(this); return this; }
+    }
+}
--- a/jdk/test/tools/jlink/IntegrationTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/IntegrationTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -59,7 +59,6 @@
  * @library ../lib
  * @modules java.base/jdk.internal.jimage
  *          jdk.jdeps/com.sun.tools.classfile
- *          jdk.jlink/jdk.tools.jlink
  *          jdk.jlink/jdk.tools.jlink.builder
  *          jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
--- a/jdk/test/tools/jlink/JLinkNegativeTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/JLinkNegativeTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -274,7 +274,7 @@
                 helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName2, classNames);
 
         try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) {
-            ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1)
+            ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1)
                     .requires("java.base").build(), out);
         }
 
@@ -332,7 +332,7 @@
                 helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName2, classNames);
 
         try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) {
-            ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1)
+            ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1)
                     .requires("java.base").build(), out);
         }
 
--- a/jdk/test/tools/jlink/JLinkTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/JLinkTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -62,9 +62,11 @@
     // number of built-in plugins from jdk.jlink module
     private static int getNumJlinkPlugins() {
         ModuleDescriptor desc = Plugin.class.getModule().getDescriptor();
-        return desc.provides().
-                    get(Plugin.class.getName()).
-                    providers().size();
+        return desc.provides().stream()
+                .filter(p -> p.service().equals(Plugin.class.getName()))
+                .map(p -> p.providers().size())
+                .findAny()
+                .orElse(0);
     }
 
     private static boolean isOfJLinkModule(Plugin p) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/basic/AllModulePath.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,178 @@
+/**
+ * Copyright (c) 2015, 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 jlink test of --add-module ALL-MODULE-PATH
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build jdk.testlibrary.ProcessTools
+ *        jdk.testlibrary.OutputAnalyzer
+ *        CompilerUtils
+ * @run testng AllModulePath
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.spi.ToolProvider;
+
+import jdk.testlibrary.ProcessTools;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class AllModulePath {
+
+    private final Path JMODS = Paths.get(System.getProperty("test.jdk")).resolve("jmods");
+    private final Path SRC = Paths.get(System.getProperty("test.src")).resolve("src");
+    private final Path MODS = Paths.get("mods");
+
+    private final static Set<String> MODULES = Set.of("test", "m1");
+
+    static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+        .orElseThrow(() ->
+            new RuntimeException("jlink tool not found")
+        );
+
+    @BeforeClass
+    public void setup() throws Throwable {
+        if (Files.notExists(JMODS)) {
+            return;
+        }
+
+        Files.createDirectories(MODS);
+
+        for (String mn : MODULES) {
+            Path mod = MODS.resolve(mn);
+            if (!CompilerUtils.compile(SRC.resolve(mn), mod)) {
+                throw new AssertionError("Compilation failure. See log.");
+            }
+        }
+    }
+
+    @Test
+    public void testAllModulePath() throws Throwable {
+        if (Files.notExists(JMODS)) {
+            return;
+        }
+
+        // create custom image
+        Path image = Paths.get("image");
+        createImage(image, "--add-modules", "ALL-MODULE-PATH");
+
+        Set<String> modules = new HashSet<>();
+        Files.find(JMODS, 1, (Path p, BasicFileAttributes attr) ->
+                                p.toString().endsWith(".jmod"))
+             .map(p -> JMODS.relativize(p).toString())
+             .map(n -> n.substring(0, n.length()-5))
+             .forEach(modules::add);
+        modules.add("m1");
+        modules.add("test");
+        checkModules(image, modules);
+    }
+
+    @Test
+    public void testLimitModules() throws Throwable {
+        if (Files.notExists(JMODS)) {
+            return;
+        }
+
+        // create custom image
+        Path image = Paths.get("image1");
+        createImage(image,
+                    "--add-modules", "ALL-MODULE-PATH",
+                    "--limit-modules", "m1");
+
+        checkModules(image, Set.of("m1", "java.base"));
+    }
+
+    @Test
+    public void testAddModules() throws Throwable {
+        if (Files.notExists(JMODS)) {
+            return;
+        }
+
+        // create custom image
+        Path image = Paths.get("image2");
+        createImage(image,
+                    "--add-modules", "m1,test",
+                    "--add-modules", "ALL-MODULE-PATH",
+                    "--limit-modules", "java.base");
+
+        checkModules(image, Set.of("m1", "test", "java.base"));
+    }
+
+    /*
+     * check the modules linked in the image
+     */
+    private void checkModules(Path image, Set<String> modules) throws Throwable {
+        Path cmd = findTool(image, "java");
+
+        List<String> options = new ArrayList<>();
+        options.add(cmd.toString());
+        options.add("-m");
+        options.add("m1/p.ListModules");
+        options.addAll(modules);
+
+        ProcessBuilder pb = new ProcessBuilder(options);
+        ProcessTools.executeCommand(pb)
+                    .shouldHaveExitValue(0);
+    }
+
+    private Path findTool(Path image, String tool)  {
+        String suffix = System.getProperty("os.name").startsWith("Windows")
+                            ? ".exe" : "";
+
+        Path cmd = image.resolve("bin").resolve(tool + suffix);
+        if (Files.notExists(cmd)) {
+            throw new RuntimeException(cmd + " not found");
+        }
+        return cmd;
+    }
+
+    private void createImage(Path image, String... options) throws IOException {
+        String modulepath = JMODS.toString() + File.pathSeparator + MODS.toString();
+        List<String> opts = List.of("--module-path", modulepath,
+                                    "--output", image.toString());
+        String[] args = Stream.concat(opts.stream(), Arrays.stream(options))
+                              .toArray(String[]::new);
+
+        System.out.println("jlink " + Arrays.stream(args).collect(Collectors.joining(" ")));
+        PrintWriter pw = new PrintWriter(System.out);
+        int rc = JLINK_TOOL.run(pw, pw, args);
+        assertTrue(rc == 0);
+    }
+}
--- a/jdk/test/tools/jlink/basic/BasicTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/basic/BasicTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -59,10 +59,11 @@
             new RuntimeException("jlink tool not found")
         );
 
+    private final String TEST_MODULE = "test";
     private final Path jdkHome = Paths.get(System.getProperty("test.jdk"));
     private final Path jdkMods = jdkHome.resolve("jmods");
     private final Path testSrc = Paths.get(System.getProperty("test.src"));
-    private final Path src = testSrc.resolve("src");
+    private final Path src = testSrc.resolve("src").resolve(TEST_MODULE);
     private final Path classes = Paths.get("classes");
     private final Path jmods = Paths.get("jmods");
     private final Path jars = Paths.get("jars");
@@ -80,23 +81,22 @@
             throw new AssertionError("Compilation failure. See log.");
         }
 
-        String modName = "test";
         Files.createDirectories(jmods);
         Files.createDirectories(jars);
         Path jarfile = jars.resolve("test.jar");
         JarUtils.createJarFile(jarfile, classes);
 
         Path image = Paths.get("mysmallimage");
-        runJmod(jarfile.toString(), modName);
-        runJlink(image, modName, "--compress", "2");
-        execute(image, modName);
+        runJmod(jarfile.toString(), TEST_MODULE);
+        runJlink(image, TEST_MODULE, "--compress", "2");
+        execute(image, TEST_MODULE);
 
-        Files.delete(jmods.resolve(modName + ".jmod"));
+        Files.delete(jmods.resolve(TEST_MODULE + ".jmod"));
 
         image = Paths.get("myimage");
-        runJmod(classes.toString(), modName);
-        runJlink(image, modName);
-        execute(image, modName);
+        runJmod(classes.toString(), TEST_MODULE);
+        runJlink(image, TEST_MODULE);
+        execute(image, TEST_MODULE);
     }
 
     private void execute(Path image, String moduleName) throws Throwable {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/basic/src/m1/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+module m1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/basic/src/m1/p/ListModules.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,48 @@
+/**
+ * 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 p;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class ListModules {
+    public static void main(String... args) {
+        Set<String> modules = ModuleFinder.ofSystem().findAll()
+            .stream()
+            .map(ModuleReference::descriptor)
+            .map(ModuleDescriptor::name)
+            .collect(Collectors.toSet());
+
+        Set<String> expected = Arrays.stream(args).collect(Collectors.toSet());
+
+        if (!modules.equals(expected)) {
+            throw new RuntimeException(modules + " != " + expected);
+        }
+
+    }
+}
--- a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -75,11 +75,11 @@
 
         String target = "target" + File.separator + name;
         Files.write(txt.toPath(), content.getBytes());
-        File lic = new File(System.getProperty("java.home"), "LICENSE");
+        File lic = new File(System.getProperty("java.home"), "LICENSE.txt");
         StringBuilder builder = new StringBuilder();
         int expected = lic.exists() ? 4 : 3;
         if (lic.exists()) {
-            builder.append("LICENSE,");
+            builder.append("LICENSE.txt,");
         }
         builder.append(txt.getAbsolutePath()+",");
         builder.append(txt.getAbsolutePath() + "=" + target+",");
@@ -116,9 +116,9 @@
         imgbuilder.storeFiles(pool);
 
         if (lic.exists()) {
-            File license = new File(root.toFile(), "LICENSE");
+            File license = new File(root.toFile(), "LICENSE.txt");
             if (!license.exists() || license.length() == 0) {
-                throw new AssertionError("Invalide license file "
+                throw new AssertionError("Invalid license file "
                         + license.getAbsoluteFile());
             }
         }
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,11 +22,10 @@
  */
 
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleDescriptor.*;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReference;
-import java.util.Collections;
-import java.util.EnumSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -58,14 +57,32 @@
     }
 
     private void testModuleDescriptor(ModuleDescriptor md) {
-        assertUnmodifiable(md.conceals(), "conceal");
         assertUnmodifiable(md.packages(), "package");
         assertUnmodifiable(md.requires(),
-                           jlma.newRequires(EnumSet.allOf(Modifier.class), "require"));
-        assertUnmodifiable(md.exports(), jlma.newExports("export"));
+                           jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require"));
+        for (Requires req : md.requires()) {
+            assertUnmodifiable(req.modifiers(), Requires.Modifier.TRANSITIVE);
+        }
+
+        assertUnmodifiable(md.exports(), jlma.newExports(Set.of(), "export", Set.of()));
+        for (Exports exp : md.exports()) {
+            assertUnmodifiable(exp.modifiers(), Exports.Modifier.SYNTHETIC);
+            assertUnmodifiable(exp.targets(), "target");
+        }
+
+        assertUnmodifiable(md.opens(), jlma.newOpens(Set.of(), "open", Set.of()));
+        for (Opens opens : md.opens()) {
+            assertUnmodifiable(opens.modifiers(), Opens.Modifier.SYNTHETIC);
+            assertUnmodifiable(opens.targets(), "target");
+        }
+
         assertUnmodifiable(md.uses(), "use");
-        assertUnmodifiable(md.provides(), "provide",
-                           jlma.newProvides("provide", Collections.singleton("provide")));
+
+        assertUnmodifiable(md.provides(),
+                           jlma.newProvides("provide", List.of("provide")));
+        for (Provides provides : md.provides()) {
+            assertUnmodifiable(provides.providers(), "provide");
+        }
 
     }
 
@@ -80,6 +97,17 @@
         }
     }
 
+    private <T> void assertUnmodifiable(List<T> list, T dummy) {
+        try {
+            list.add(dummy);
+            fail("Should throw UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            // pass
+        } catch (Exception e) {
+            fail("Should throw UnsupportedOperationException");
+        }
+    }
+
     private <T, V> void assertUnmodifiable(Map<T, V> set, T dummyKey, V dummyValue) {
         try {
             set.put(dummyKey, dummyValue);
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -52,9 +52,11 @@
     private static final Path MODS_DIR = Paths.get("mods");
     private static final Path IMAGE = Paths.get("image");
     private static final Path JMODS = Paths.get(JAVA_HOME, "jmods");
+    private static final String MAIN_MID = "m1/p1.Main";
 
     // the names of the modules in this test
-    private static String[] modules = new String[] {"m1", "m2", "m3"};
+    private static String[] modules = new String[] {"m1", "m2", "m3", "m4"};
+
 
     private static boolean hasJmods() {
         if (!Files.exists(JMODS)) {
@@ -80,7 +82,7 @@
             FileUtils.deleteFileTreeUnchecked(IMAGE);
         }
 
-        createImage(IMAGE, "java.base", "m1");
+        createImage(IMAGE, "java.base", "m1", "m3");
     }
 
     private void createImage(Path outputDir, String... modules) throws Throwable {
@@ -96,20 +98,34 @@
 
     /*
      * Test the image created when linking with a module with
-     * no ConcealedPackages attribute
+     * no Packages attribute
      */
     @Test
-    public void test() throws Throwable {
+    public void testPackagesAttribute() throws Throwable {
         if (!hasJmods()) return;
 
         Path java = IMAGE.resolve("bin").resolve("java");
-        assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main")
+        assertTrue(executeProcess(java.toString(), "-m", MAIN_MID)
                         .outputTo(System.out)
                         .errorTo(System.out)
                         .getExitValue() == 0);
     }
 
     /*
+     * Test the image created when linking with an open module
+    */
+    @Test
+    public void testOpenModule() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path java = IMAGE.resolve("bin").resolve("java");
+        assertTrue(executeProcess(java.toString(), "-m", "m3/p3.Main")
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .getExitValue() == 0);
+    }
+
+    /*
      * Disable the fast loading of system modules.
      * Parsing module-info.class
      */
@@ -120,7 +136,7 @@
         Path java = IMAGE.resolve("bin").resolve("java");
         assertTrue(executeProcess(java.toString(),
                                   "-Djdk.system.module.finder.disabledFastPath",
-                                  "-m", "m1/p1.Main")
+                                  "-m", MAIN_MID)
                         .outputTo(System.out)
                         .errorTo(System.out)
                         .getExitValue() == 0);
@@ -135,9 +151,9 @@
         if (!hasJmods()) return;
 
         Path dir = Paths.get("newImage");
-        createImage(dir, "java.base", "m1", "m2", "m3");
+        createImage(dir, "java.base", "m1", "m2", "m3", "m4");
         Path java = dir.resolve("bin").resolve("java");
-        assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main")
+        assertTrue(executeProcess(java.toString(), "-m", MAIN_MID)
                         .outputTo(System.out)
                         .errorTo(System.out)
                         .getExitValue() == 0);
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -48,7 +48,6 @@
     }
 
     static void validate(ModuleDescriptor md) {
-        checkPackages(md.conceals(), "p1", "p2");
         checkPackages(md.packages(), "p1", "p2");
     }
 
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,4 +22,5 @@
  */
 
 module m3 {
+    requires m4;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,74 @@
+/*
+ * 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 p3;
+
+import p4.Foo;
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Module;
+
+import static java.lang.module.ModuleDescriptor.Exports.Modifier.*;
+
+/**
+ * Test if m4 is an open module and p4 is package that m3 can access
+ */
+public class Main {
+    public static void main(String... args) throws Exception {
+        Module m4 = Foo.class.getModule();
+        if (!m4.isOpen("p4")) {
+            throw new RuntimeException("m3 can't access p4");
+        }
+
+        // Test if it can access a private field
+        Foo foo = Foo.create("foo");
+
+        Field field = Foo.class.getDeclaredField("name");
+        field.setAccessible(true);
+        String name = (String) field.get(foo);
+        if (!name.equals("foo")) {
+            throw new RuntimeException("unexpected Foo::name value = " + name);
+        }
+
+        checkOpenModule();
+    }
+
+    // check the module descriptor of the open module m4
+    static void checkOpenModule() {
+        ModuleDescriptor md = Foo.class.getModule().getDescriptor();
+        System.out.println(md);
+
+        if (!md.isOpen()) {
+            throw new RuntimeException("m4 is a open module");
+        }
+
+        if (md.packages().size() != 1 || !md.packages().contains("p4")) {
+            throw new RuntimeException("unexpected m4 packages: " + md.packages());
+        }
+
+        if (!md.opens().isEmpty()) {
+            throw new RuntimeException("unexpected m4 opens: " + md.opens());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+open module m4 {
+    exports p4;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Foo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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 p4;
+
+public class Foo {
+    private final String name;
+
+    private Foo(String name) {
+        this.name = name;
+    }
+
+    public static Foo create(String name) {
+        return new Foo(name);
+    }
+}
--- a/jdk/test/tools/jmod/JmodTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jmod/JmodTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,13 +23,13 @@
 
 /*
  * @test
+ * @bug 8142968
+ * @summary Basic test for jmod
  * @library /lib/testlibrary
  * @modules jdk.compiler
  *          jdk.jlink
  * @build jdk.testlibrary.FileUtils CompilerUtils
  * @run testng JmodTest
- * @bug 8142968
- * @summary Basic test for jmod
  */
 
 import java.io.*;
@@ -76,6 +76,9 @@
         for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) {
             Path dir = EXPLODED_DIR.resolve(name);
             assertTrue(compileModule(name, dir.resolve("classes")));
+            copyResource(SRC_DIR.resolve("foo"),
+                         dir.resolve("classes"),
+                         "jdk/test/foo/resources/foo.properties");
             createCmds(dir.resolve("bin"));
             createLibs(dir.resolve("lib"));
             createConfigs(dir.resolve("conf"));
@@ -127,6 +130,7 @@
                 assertContains(r.output, CLASSES_PREFIX + "module-info.class");
                 assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class");
                 assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");
+                assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");
             });
     }
 
@@ -279,6 +283,7 @@
                  Set<String> expectedFilenames = new HashSet<>();
                  expectedFilenames.add(CLASSES_PREFIX + "module-info.class");
                  expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class");
+                 expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");
                  expectedFilenames.add(LIBS_PREFIX + "second.so");
                  expectedFilenames.add(LIBS_PREFIX + "third/third.so");
                  assertJmodContent(jmod, expectedFilenames);
@@ -303,15 +308,15 @@
              .assertSuccess()
              .resultChecker(r -> {
                  // Expect similar output: "foo,  requires mandated java.base
-                 // exports jdk.test.foo,  conceals jdk.test.foo.internal"
+                 // exports jdk.test.foo,  contains jdk.test.foo.internal"
                  Pattern p = Pattern.compile("\\s+foo\\s+requires\\s+mandated\\s+java.base");
                  assertTrue(p.matcher(r.output).find(),
                            "Expecting to find \"foo, requires java.base\"" +
                                 "in output, but did not: [" + r.output + "]");
                  p = Pattern.compile(
-                        "exports\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal");
+                        "exports\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal");
                  assertTrue(p.matcher(r.output).find(),
-                           "Expecting to find \"exports ..., conceals ...\"" +
+                           "Expecting to find \"exports ..., contains ...\"" +
                                 "in output, but did not: [" + r.output + "]");
              });
     }
@@ -369,6 +374,26 @@
     }
 
     @Test
+    public void testPackagesAttribute() throws IOException {
+        Path jmod = MODS_DIR.resolve("foo.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+        Set<String> expectedPackages = Set.of("jdk.test.foo",
+                                              "jdk.test.foo.internal",
+                                              "jdk.test.foo.resources");
+
+        jmod("create",
+             "--class-path", cp,
+             jmod.toString())
+             .assertSuccess()
+             .resultChecker(r -> {
+                 Set<String> pkgs = getModuleDescriptor(jmod).packages();
+                 assertEquals(pkgs, expectedPackages);
+             });
+        }
+
+    @Test
     public void testVersion() {
         jmod("--version")
             .assertSuccess()
@@ -557,6 +582,14 @@
         }
     }
 
+    static void copyResource(Path srcDir, Path dir, String resource) throws IOException {
+        Path dest = dir.resolve(resource);
+        Files.deleteIfExists(dest);
+
+        Files.createDirectories(dest.getParent());
+        Files.copy(srcDir.resolve(resource), dest);
+    }
+
     // Standalone entry point.
     public static void main(String[] args) throws Throwable {
         JmodTest test = new JmodTest();
--- a/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,5 +22,5 @@
  */
 
 module org.bar {
-    requires public m1;
+    requires transitive m1;
 }
--- a/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,5 +22,5 @@
  */
 
 module org.foo {
-    requires public org.bar;
+    requires transitive org.bar;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/src/foo/jdk/test/foo/resources/foo.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,1 @@
+name = foo 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/InfoStreams.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,78 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @build InfoStreams jdk.testlibrary.ProcessTools
+ * @run main InfoStreams
+ * @summary Test that informational options use the correct streams
+ */
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.OutputAnalyzer;
+
+
+public class InfoStreams {
+
+    public static OutputAnalyzer run(String ... opts) throws Exception {
+        return ProcessTools.executeTestJava(opts).shouldHaveExitValue(0);
+    }
+
+    private static final String
+        java_version = System.getProperty("java.version"),
+        USAGE = "^Usage: java ",
+        VERSION_ERR = "^(java|openjdk) version \"" + java_version + "\"",
+        VERSION_OUT = "^(java|openjdk) " + java_version,
+        FULLVERSION_ERR = "^(java|openjdk) full version \"" + java_version + ".*\"",
+        FULLVERSION_OUT = "^(java|openjdk) " + java_version,
+        NONSTD = ".*These extra options are subject to change";
+
+    public static void main(String ... args) throws Exception {
+
+        String classPath = System.getProperty("java.class.path");
+
+        run("-help").stderrShouldMatch(USAGE).stdoutShouldNotMatch(".");
+        run("--help").stdoutShouldMatch(USAGE).stderrShouldNotMatch(".");
+
+        run("-version").stderrShouldMatch(VERSION_ERR).stdoutShouldNotMatch(".");
+        run("--version").stdoutShouldMatch(VERSION_OUT).stderrShouldNotMatch(".");
+
+        run("-showversion", "--dry-run", "-cp", classPath, "InfoStreams")
+            .stderrShouldMatch(VERSION_ERR)
+            .stdoutShouldNotMatch(".");
+        run("--show-version", "--dry-run", "-cp", classPath, "InfoStreams")
+            .stdoutShouldMatch(VERSION_OUT)
+            .stderrShouldNotMatch(".");
+
+        run("-fullversion").stderrShouldMatch(FULLVERSION_ERR)
+            .stdoutShouldNotMatch(".");
+        run("--full-version").stdoutShouldMatch(FULLVERSION_OUT)
+            .stderrShouldNotMatch(".");
+
+        run("-X").stderrShouldMatch(NONSTD).stdoutShouldNotMatch(".");
+        run("--help-extra").stdoutShouldMatch(NONSTD).stderrShouldNotMatch(".");
+
+    }
+
+}
--- a/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -32,7 +32,9 @@
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.stream.Stream;
 
+import jdk.testlibrary.OutputAnalyzer;
 import static jdk.testlibrary.ProcessTools.*;
 
 import org.testng.annotations.BeforeTest;
@@ -202,13 +204,15 @@
 
 
     /**
-     * --add-exports allows duplicates
+     * --add-exports and --add-opens allows duplicates
      */
     public void testWithDuplicateOption() throws Exception {
 
         int exitValue
             =  executeTestJava("--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
                                "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
+                               "--add-opens", "java.base/java.util=ALL-UNNAMED",
+                               "--add-opens", "java.base/java.util=ALL-UNNAMED",
                                "-version")
                 .outputTo(System.out)
                 .errorTo(System.out)
@@ -218,23 +222,33 @@
     }
 
 
+    private OutputAnalyzer execJava(String... options) {
+        try {
+            return executeTestJava(options);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+
     /**
-     * Exercise --add-exports with unknown values.  Warning is emitted.
+     * Exercise --add-exports and --add-opens with unknown values.
+     * Warning is emitted.
      */
     @Test(dataProvider = "unknownvalues")
-    public void testWithUnknownValue(String value, String ignore) throws Exception {
+    public void testWithUnknownValue(String value, String ignore) {
+        Stream.of("--add-exports", "--add-opens")
+            .forEach(option -> {
+                //  --add-exports $VALUE -version
+                int exitValue = execJava(option, value, "-version")
+                    .stderrShouldMatch("WARNING: .*.monkey.*")
+                    .outputTo(System.out)
+                    .errorTo(System.out)
+                    .getExitValue();
 
-        //  --add-exports $VALUE -version
-        int exitValue =
-            executeTestJava("--add-exports", value,
-                            "-version")
-                .stderrShouldMatch("WARNING: .*.monkey.*")
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
+                assertTrue(exitValue == 0);
+            });
+    }
 
-        assertTrue(exitValue == 0);
-    }
 
     @DataProvider(name = "unknownvalues")
     public Object[][] unknownValues() {
@@ -250,20 +264,20 @@
 
 
     /**
-     * Exercise --add-exports with bad values
+     * Exercise --add-exports and --add-opens with bad values
      */
     @Test(dataProvider = "badvalues")
-    public void testWithBadValue(String value, String ignore) throws Exception {
-
-        //  --add-exports $VALUE -version
-        int exitValue =
-            executeTestJava("--add-exports", value,
-                            "-version")
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
+    public void testWithBadValue(String value, String ignore) {
+        Stream.of("--add-exports", "--add-opens")
+            .forEach(option -> {
+                //  --add-exports $VALUE -version
+                int exitValue = execJava(option, value, "-version")
+                    .outputTo(System.out)
+                    .errorTo(System.out)
+                    .getExitValue();
 
         assertTrue(exitValue != 0);
+            });
     }
 
     @DataProvider(name = "badvalues")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addexports/manifest/AddExportsAndOpensInManifest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,175 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build AddExportsAndOpensInManifest Test2 JarUtils jdk.testlibrary.*
+ * @compile --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED Test1.java
+ * @run testng AddExportsAndOpensInManifest
+ * @summary Basic test for Add-Exports and Add-Opens attributes in the
+ *          manifest of a main application JAR
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+@Test
+public class AddExportsAndOpensInManifest {
+
+    /**
+     * Package Test1 and Test2 into a JAR file with the given attributes
+     * in the JAR manifest, then execute the JAR file with `java -jar`.
+     */
+    private OutputAnalyzer runTest(String attributes) throws Exception {
+        Manifest man = new Manifest();
+        Attributes attrs = man.getMainAttributes();
+        attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+
+        for (String nameAndValue : attributes.split(",")) {
+            String[] s = nameAndValue.split("=");
+            if (s.length != 2)
+                throw new RuntimeException("Malformed: " + nameAndValue);
+            String name = s[0];
+            String value = s[1];
+            attrs.put(new Attributes.Name(name), value);
+        }
+
+        // create the JAR file with Test1 and Test2
+        Path jarfile = Paths.get("test.jar");
+        Files.deleteIfExists(jarfile);
+
+        Path classes = Paths.get(System.getProperty("test.classes", ""));
+        JarUtils.createJarFile(jarfile, man, classes,
+                Paths.get("Test1.class"), Paths.get("Test2.class"));
+
+        // java -jar test.jar
+        return ProcessTools.executeTestJava("-jar", jarfile.toString())
+                .outputTo(System.out)
+                .errorTo(System.out);
+    }
+
+    /**
+     * Run test with the given JAR attributes, expecting the test to pass
+     */
+    private void runExpectingPass(String attrs) throws Exception {
+        int exitValue = runTest(attrs).getExitValue();
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Run test with the given JAR attributes, expecting the test to fail
+     * with at least the given output
+     */
+    private void runExpectingFail(String attrs, String errorString) throws Exception {
+        int exitValue = runTest(attrs).shouldContain(errorString).getExitValue();
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Run tests to make sure that they fail in the expected way.
+     */
+    public void testSanity() throws Exception {
+        runExpectingFail("Main-Class=Test1", "IllegalAccessError");
+        runExpectingFail("Main-Class=Test2", "InaccessibleObjectException");
+    }
+
+    /**
+     * Run tests with the Add-Exports attribute in the main manifest.
+     */
+    public void testWithAddExports() throws Exception {
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc");
+        runExpectingFail("Main-Class=Test2,Add-Exports=java.base/jdk.internal.misc",
+                         "InaccessibleObjectException");
+
+        // run with leading and trailing spaces
+        runExpectingPass("Main-Class=Test1,Add-Exports=  java.base/jdk.internal.misc");
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc  ");
+
+        // run with multiple values
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc"
+                + " java.base/jdk.internal.loader");
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.loader"
+                + " java.base/jdk.internal.misc");
+
+        // run with duplicate values
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc"
+                + " java.base/jdk.internal.misc");
+    }
+
+    /**
+     * Run tests with the Add-Opens attribute in the main manifest.
+     */
+    public void testWithAddOpens() throws Exception {
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc");
+        runExpectingPass("Main-Class=Test2,Add-Opens=java.base/jdk.internal.misc");
+
+        // run with leading and trailing spaces
+        runExpectingPass("Main-Class=Test1,Add-Opens=  java.base/jdk.internal.misc");
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc  ");
+
+        // run with multiple values
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc"
+                + " java.base/jdk.internal.loader");
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.loader"
+                + " java.base/jdk.internal.misc");
+
+        // run with duplicate values
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc"
+                + " java.base/jdk.internal.misc");
+    }
+
+    /**
+     * Run tests a bad module or package name
+     */
+    public void testWithBadModuleOrPackage() throws Exception {
+        // Add-Exports with bad module name
+        String attrs = "Main-Class=Test1,Add-Exports=java.DoesNotExist/jdk.internal.misc";
+        runExpectingFail(attrs, "IllegalAccessError");
+
+        // Add-Exports with bad package name
+        attrs = "Main-Class=Test1,Add-Exports=java.base/jdk.internal.DoesNotExit";
+        runExpectingFail(attrs, "IllegalAccessError");
+
+        // Add-Opens with bad module name
+        attrs = "Main-Class=Test1,Add-Opens=java.DoesNotExist/jdk.internal.misc";
+        runExpectingFail(attrs, "IllegalAccessError");
+
+        // Add-Opens with bad package name
+        attrs = "Main-Class=Test1,Add-Opens=java.base/jdk.internal.DoesNotExit";
+        runExpectingFail(attrs, "IllegalAccessError");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addexports/manifest/Test1.java	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,30 @@
+/**
+ * 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.internal.misc.Unsafe;
+
+public class Test1 {
+    public static void main(String[] args) throws Exception {
+        Unsafe unsafe = Unsafe.getUnsafe();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addexports/manifest/Test2.java	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+import java.lang.reflect.Field;
+
+/**
+ * Use core reflection and setAccessible(true) to access private field.
+ */
+
+public class Test2 {
+    public static void main(String[] args) throws Exception {
+        Class<?> c = Class.forName("jdk.internal.misc.Unsafe");
+        Field f = c.getDeclaredField("theUnsafe");
+        f.setAccessible(true);
+        Object unsafe = f.get(null);
+    }
+}
--- a/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,13 +23,10 @@
 
 package jdk.test1;
 
-import java.lang.reflect.Field;
 import jdk.internal.misc.Unsafe;
 
 public class Main {
     public static void main(String[] args) throws Exception {
-        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-        theUnsafe.setAccessible(true);
-        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
+        Unsafe unsafe = Unsafe.getUnsafe();
     }
 }
--- a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -115,7 +115,7 @@
                 .outputTo(System.out)
                 .errorTo(System.out);
         output.shouldNotContain("java.base");
-        output.shouldNotContain("java.rhubarb");
+        output.shouldContain("java.rhubarb not observable");
         assertTrue(output.getExitValue() == 0);
     }
 
--- a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -22,6 +22,6 @@
  */
 
 module java.transaction {
-    requires public java.enterprise;
+    requires transitive java.enterprise;
     exports javax.transaction;
 }
--- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -39,7 +39,6 @@
 import com.sun.tools.classfile.ClassFile;
 import com.sun.tools.classfile.Code_attribute;
 import com.sun.tools.classfile.CompilationID_attribute;
-import com.sun.tools.classfile.ConcealedPackages_attribute;
 import com.sun.tools.classfile.ConstantPool;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
@@ -65,8 +64,6 @@
 import com.sun.tools.classfile.EnclosingMethod_attribute;
 import com.sun.tools.classfile.Exceptions_attribute;
 import com.sun.tools.classfile.Field;
-import com.sun.tools.classfile.Hashes_attribute;
-import com.sun.tools.classfile.Hashes_attribute.Entry;
 import com.sun.tools.classfile.InnerClasses_attribute;
 import com.sun.tools.classfile.InnerClasses_attribute.Info;
 import com.sun.tools.classfile.Instruction;
@@ -74,13 +71,18 @@
 import com.sun.tools.classfile.LineNumberTable_attribute;
 import com.sun.tools.classfile.LocalVariableTable_attribute;
 import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
-import com.sun.tools.classfile.MainClass_attribute;
 import com.sun.tools.classfile.Method;
 import com.sun.tools.classfile.MethodParameters_attribute;
 import com.sun.tools.classfile.Module_attribute;
 import com.sun.tools.classfile.Module_attribute.ExportsEntry;
 import com.sun.tools.classfile.Module_attribute.ProvidesEntry;
 import com.sun.tools.classfile.Module_attribute.RequiresEntry;
+import com.sun.tools.classfile.ModuleHashes_attribute;
+import com.sun.tools.classfile.ModuleHashes_attribute.Entry;
+import com.sun.tools.classfile.ModuleMainClass_attribute;
+import com.sun.tools.classfile.ModuleTarget_attribute;
+import com.sun.tools.classfile.ModulePackages_attribute;
+import com.sun.tools.classfile.ModuleVersion_attribute;
 import com.sun.tools.classfile.Opcode;
 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
@@ -102,11 +104,9 @@
 import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame_extended;
 import com.sun.tools.classfile.StackMap_attribute;
 import com.sun.tools.classfile.Synthetic_attribute;
-import com.sun.tools.classfile.TargetPlatform_attribute;
 import com.sun.tools.classfile.TypeAnnotation;
 import com.sun.tools.classfile.TypeAnnotation.Position;
 import static com.sun.tools.classfile.TypeAnnotation.TargetType.THROWS;
-import com.sun.tools.classfile.Version_attribute;
 import java.io.*;
 import java.util.*;
 import java.util.jar.JarEntry;
@@ -1017,7 +1017,7 @@
     }
 
     @Override
-    public Element visitConcealedPackages(ConcealedPackages_attribute attr, Element p) {
+    public Element visitModulePackages(ModulePackages_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         for (int i : attr.packages_index) {
             Element ee = new Element("Package");
@@ -1128,7 +1128,7 @@
         for (ExportsEntry export : exports) {
             Element exto = new Element("exports");
             exto.setAttr("package", x.getCpString(export.exports_index));
-            for ( int idx : export.exports_to_index) {
+            for (int idx : export.exports_to_index) {
                 exto.setAttr("module", x.getCpString(idx));
             }
             ex.add(exto);
@@ -1140,7 +1140,9 @@
         Element ex = new Element("Provides");
         for (ProvidesEntry provide : provides) {
             ex.setAttr("provides", x.getCpString(provide.provides_index));
-            ex.setAttr("with", x.getCpString(provide.with_index));
+            for (int idx : provide.with_index) {
+                ex.setAttr("with", x.getCpString(idx));
+            }
         }
         p.add(ex);
     }
@@ -1461,14 +1463,20 @@
     }
 
     @Override
-    public Element visitHashes(Hashes_attribute attr, Element p) {
+    public Element visitModuleHashes(ModuleHashes_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         e.setAttr("Algorithm", x.getCpString(attr.algorithm_index));
         for (Entry entry : attr.hashes_table) {
             Element ee = new Element("Entry");
-            String requires = x.getCpString(entry.requires_index);
-            String hashValue = x.getCpString(entry.hash_index);
-            ee.setAttr(requires, hashValue);
+            String mn = x.getCpString(entry.module_name_index);
+            ee.setAttr("module_name", mn);
+            ee.setAttr("hash_length", "" + entry.hash.length);
+            StringBuilder sb = new StringBuilder();
+            for (byte b: entry.hash) {
+                sb.append(String.format("%02x", b & 0xff));
+            }
+            ee.setAttr("hash", sb.toString());
+            ee.trimToSize();
             e.add(ee);
         }
         e.trimToSize();
@@ -1478,7 +1486,7 @@
     }
 
     @Override
-    public Element visitMainClass(MainClass_attribute attr, Element p) {
+    public Element visitModuleMainClass(ModuleMainClass_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         e.add(x.getCpString(attr.main_class_index));
         e.trimToSize();
@@ -1487,7 +1495,7 @@
     }
 
     @Override
-    public Element visitTargetPlatform(TargetPlatform_attribute attr, Element p) {
+    public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         e.add(x.getCpString(attr.os_name_index));
         e.add(x.getCpString(attr.os_arch_index));
@@ -1498,7 +1506,7 @@
     }
 
     @Override
-    public Element visitVersion(Version_attribute attr, Element p) {
+    public Element visitModuleVersion(ModuleVersion_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         e.add(x.getCpString(attr.version_index));
         e.trimToSize();
@@ -1813,7 +1821,7 @@
 
     @Override
     public Element visitArray(Array_element_value a, Element p) {
-     Element el = new Element("Array");
+        Element el = new Element("Array");
         for (Annotation.element_value v : a.values) {
            Element child = visit(v, el);
            if (child != null) {
--- a/make/CompileJavaModules.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/CompileJavaModules.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -356,10 +356,6 @@
 
 ################################################################################
 
-jdk.jshell_ADD_JAVAC_FLAGS := -Xlint:-exports
-
-################################################################################
-
 jdk.hotspot.agent_ADD_JAVAC_FLAGS := $(DISABLE_WARNINGS),-overrides
 jdk.hotspot.agent_COPY := .gif .png sa.js .properties
 
--- a/make/CreateHgtipFiles.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-#
-# 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.
-#
-
-default: all
-
-include $(SPEC)
-include MakeBase.gmk
-
-define SetupCreateHgtip
-
-  $$(strip $1)/$(HGTIP_FILENAME): FRC
-	$(HG) tip --repository $$(strip $1) --template '{node|short}\n' > $$@.tmp
-	if [ ! -f $$@ ] || [ "`$(CAT) $$@`" != "`$(CAT) $$@.tmp`" ]; then \
-	  $(MV) $$@.tmp $$@ ; \
-	else \
-	  $(RM) $$@.tmp ; \
-	fi
-
-  TARGETS += $$(strip $1)/$(HGTIP_FILENAME)
-
-endef
-
-# Only try to create the tips if finding an actual hg repository. This will be
-# false if building from a source bundle.
-$(foreach r, $(call FindAllReposAbs), \
-  $(if $(wildcard $r/.hg), $(eval $(call SetupCreateHgtip, $r))) \
-)
-
-all: $(TARGETS)
-
-FRC:
-
-.PHONY: all
--- a/make/GensrcModuleInfo.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/GensrcModuleInfo.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -60,8 +60,8 @@
 
 ################################################################################
 
-# Name of data file. Keep module-info.java.ext until javafx has changed.
-MOD_FILENAME := module-info.java.extra module-info.java.ext
+# Name of modification file.
+MOD_FILENAME := module-info.java.extra
 
 # Construct all possible src directories for the module.
 MODULE_CLASSES_DIRS := $(call FindModuleSrcDirs, $(MODULE))
@@ -74,74 +74,24 @@
   # Only make this call if modification files are found for this module
   ALL_MODULES := $(call FindAllModules)
 
-  # Read the contents of all the files into a variable. Replace space with / to
-  # let space represent new lines in the variable as $(shell) normalizes all
-  # whitespace.
-  $(foreach f, $(MOD_FILES), \
-    $(eval MOD_FILE_CONTENTS += $(shell $(GREP) -v -e ".\*" -e "//" $f | $(TR) ' ' '/')))
-
-  # Separate the modifications into qualified exports and the rest
-  MODS_QUALIFIED_EXPORTS := $(call containing, /to/, $(MOD_FILE_CONTENTS))
-  MODS_REST := $(filter-out $(MODS_QUALIFIED_EXPORTS), $(MOD_FILE_CONTENTS))
-
-  # Filter the contents for modules that are actually being built
-  ALL_MODULES_FILTER := $(addprefix %/, $(addsuffix ;, $(ALL_MODULES)))
-  MODIFICATIONS := $(filter $(ALL_MODULES_FILTER), $(MODS_QUALIFIED_EXPORTS)) \
-      $(MODS_REST)
-
-  # Returns non empty if the package exists in the current module
-  # Param 1 - Name of package with dots
-  PackageExists = \
-      $(strip $(wildcard $(addsuffix $(subst .,/,/$(strip $1)), \
-          $(MODULE_CLASSES_DIRS) \
-          $(addsuffix /$(MODULE), $(IMPORT_MODULES_CLASSES)) \
-          $(JDK_OUTPUTDIR)/modules/$(MODULE) \
-      )))
-
-  # Convert the modification lines into arguments for the modification tool.
-  # Filter out modifications for non existing to-modules.
-  $(foreach line, $(MODIFICATIONS), \
-    $(eval split_line := $(subst /,$(SPACE),$(line))) \
-    $(eval command := $(word 1, $(split_line))) \
-    $(if $(filter $(command), exports), \
-      $(eval package := $(patsubst %;,%,$(word 2, $(split_line)))) \
-      $(if $(call PackageExists, $(package)), \
-        $(eval to_module := $(patsubst %;,%,$(word 4, $(split_line)))) \
-        $(if $(to_module), \
-          $(eval ARGS += -$(command) $(package)/$(to_module)) \
-        , \
-          $(eval ARGS += -$(command) $(package)) \
-        ) \
-      ) \
-    , \
-      $(if $(filter $(command), provides), \
-        $(eval provider := $(patsubst %;,%,$(word 2, $(split_line)))) \
-        $(eval class := $(patsubst %;,%,$(word 4, $(split_line)))) \
-        $(eval ARGS += -$(command) $(provider)/$(class)) \
-      , \
-        $(error A module-info.extra in $(MODULE) contains invalid command $(command)) \
-      ) \
-    ) \
-  )
-
-  ifneq ($(ARGS), )
-    $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java: \
-        $(firstword $(call FindAllModuleInfos, $(MODULE))) \
-        $(BUILD_TOOLS_JDK) \
-        $(call DependOnVariable, ARGS)
+  $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java: \
+      $(firstword $(call FindAllModuleInfos, $(MODULE))) \
+      $(BUILD_TOOLS_JDK) \
+      $(MOD_FILES) \
+      $(call DependOnVariable, ALL_MODULES)
 		$(MKDIR) -p $(@D)
 		$(RM) $@ $@.tmp
-		$(TOOL_GENMODULEINFOSOURCE) $(ARGS) -o $@.tmp $<
+		$(TOOL_GENMODULEINFOSOURCE) -o $@.tmp \
+		    --source-file $< \
+		    --modules $(call CommaList, $(ALL_MODULES)) \
+		    $(MOD_FILES)
 		$(MV) $@.tmp $@
 
-    TARGETS += $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java
-  endif
+  TARGETS += $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java
 
-endif
-
-# If no modifications are found for this module, remove any module-info.java
-# created by a previous build since that is no longer valid.
-ifeq ($(MODIFICATIONS), )
+else
+  # If no modifications are found for this module, remove any module-info.java
+  # created by a previous build since that is no longer valid.
   ifneq ($(wildcard $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java), )
     $(shell $(RM) $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java)
   endif
--- a/make/Images.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/Images.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -48,7 +48,8 @@
 JDK_MODULES += $(ALL_MODULES)
 
 # Compact builds have additional modules
-COMPACT1_EXTRA_MODULES := jdk.localedata jdk.crypto.pkcs11 jdk.crypto.ec
+COMPACT1_EXTRA_MODULES := jdk.localedata jdk.crypto.pkcs11 jdk.crypto.ec \
+    jdk.unsupported
 COMPACT2_EXTRA_MODULES := jdk.xml.dom jdk.httpserver
 COMPACT3_EXTRA_MODULES := java.smartcardio jdk.management \
     jdk.naming.dns jdk.naming.rmi jdk.sctp jdk.security.auth
@@ -64,47 +65,9 @@
 JRE_COMPACT3_MODULES_LIST := $(call CommaList, $(JRE_COMPACT3_MODULES))
 
 ################################################################################
-# Release file
 
 BASE_RELEASE_FILE := $(JDK_OUTPUTDIR)/release
 
-# Common way to emit a line into the release or info file
-define info-file-item # name value
-  $(PRINTF) '%s="%s"\n' $1 $2 >> $@
-endef
-
-# Param 1 - The file containing the MODULES list
-define create-info-file
-  $(if $(JDK_ARCH_ABI_PROP_NAME), \
-    $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)"))
-  $(call info-file-item, "SOURCE", "$(strip $(ALL_SOURCE_TIPS))")
-endef
-
-# Param 1 - The file containing the MODULES list
-define prepare-info-file
-  $(ECHO) $(LOG_INFO) Generating $(patsubst $(OUTPUT_ROOT)/%,%,$@)
-  $(MKDIR) -p $(@D)
-  $(RM) $@
-endef
-
-define info-file
-  $(call prepare-info-file)
-  $(call create-info-file)
-endef
-
-# Create a variable dependency file common for all release info files.
-INFO_FILE_VARDEPS := $(call DependOnVariable, create-info-file)
-
-ALL_SOURCE_TIPS = $(shell \
-    if [ -f $(SUPPORT_OUTPUTDIR)/source_tips ] ; then \
-      $(CAT) $(SUPPORT_OUTPUTDIR)/source_tips ; \
-    fi)
-
-$(BASE_RELEASE_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips
-	$(info-file)
-
-################################################################################
-
 JMODS := $(wildcard $(IMAGES_OUTPUTDIR)/jmods/*.jmod)
 
 # Use this file inside the image as target for make rule
@@ -124,7 +87,8 @@
     /jdk.localedata/** \
     #
 
-JLINK_TOOL := $(JLINK) --module-path $(IMAGES_OUTPUTDIR)/jmods \
+JLINK_TOOL := $(JLINK) -J-Djlink.debug=true \
+    --module-path $(IMAGES_OUTPUTDIR)/jmods \
     --endian $(OPENJDK_BUILD_CPU_ENDIAN) \
     --release-info $(BASE_RELEASE_FILE) \
     --order-resources=$(call CommaList, $(JLINK_ORDER_RESOURCES)) \
@@ -400,16 +364,6 @@
 JDK_TARGETS += $(COPY_SAMPLES)
 
 ################################################################################
-# jrt-fs.jar
-
-$(eval $(call SetupCopyFiles,COPY_JRTFS_JAR, \
-    SRC := $(SUPPORT_OUTPUTDIR), \
-    DEST := $(JDK_IMAGE_DIR), \
-    FILES := $(SUPPORT_OUTPUTDIR)/jrt-fs.jar))
-
-JDK_TARGETS += $(COPY_JRTFS_JAR)
-
-################################################################################
 # Code coverage data files
 
 ifeq ($(GCOV_ENABLED), true)
--- a/make/Init.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/Init.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -157,7 +157,7 @@
     # Do not let make delete spec files even if aborted while doing a reconfigure
     .PRECIOUS: $(SPECS)
 
-    # Unless reconfigure is explicitely called, let all main targets depend on
+    # Unless reconfigure is explicitly called, let all main targets depend on
     # the spec files to be up to date.
     ifeq ($(findstring reconfigure, $(INIT_TARGETS)), )
       $(MAIN_TARGETS): $(SPECS)
@@ -278,7 +278,7 @@
 
   # MAKEOVERRIDES is automatically set and propagated by Make to sub-Make calls.
   # We need to clear it of the init-specific variables. The user-specified
-  # variables are explicitely propagated using $(USER_MAKE_VARS).
+  # variables are explicitly propagated using $(USER_MAKE_VARS).
   main: MAKEOVERRIDES :=
 
   main: $(INIT_TARGETS)
--- a/make/Javadoc.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/Javadoc.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -33,7 +33,7 @@
 # Allow custom to overwrite.
 JAVADOC_SOURCE_DIRS = \
       $(SUPPORT_OUTPUTDIR)/gensrc/* \
-      $(if $(IMPORT_MODULES_SRC), $(IMPORT_MODULES_SRC)/*) \
+      $(addsuffix /*, $(IMPORT_MODULES_SRC)) \
       $(JDK_TOPDIR)/src/*/$(OPENJDK_TARGET_OS)/classes \
       $(JDK_TOPDIR)/src/*/$(OPENJDK_TARGET_OS_TYPE)/classes \
       $(JDK_TOPDIR)/src/*/share/classes \
--- a/make/JrtfsJar.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/JrtfsJar.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -65,7 +65,7 @@
 $(eval $(call SetupJarArchive,BUILD_JRTFS_JAR, \
     DEPENDENCIES := $(BUILD_JRTFS) $(COPY_JIMAGE_SERVICE_PROVIDER), \
     SRCS := $(SUPPORT_OUTPUTDIR)/jrtfs_classes, \
-    JAR := $(SUPPORT_OUTPUTDIR)/jrt-fs.jar, \
+    JAR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jrt-fs.jar, \
     MANIFEST := $(SUPPORT_OUTPUTDIR)/java-main-manifest.mf, \
 ))
 
--- a/make/Main.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/Main.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -284,16 +284,11 @@
 ################################################################################
 # Images targets
 
-# Stores the tips for each repository. This file is be used when constructing
-# the jdk image and can be used to track the exact sources used to build that
-# image.
-source-tips: $(SUPPORT_OUTPUTDIR)/source_tips
-$(SUPPORT_OUTPUTDIR)/source_tips: FRC
-	$(call MakeDir, $(@D))
-	$(call GetSourceTips)
+store-source-revision:
+	+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f SourceRevision.gmk store-source-revision)
 
-create-hgtip-files:
-	+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f CreateHgtipFiles.gmk)
+create-source-revision-tracker:
+	+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f SourceRevision.gmk create-source-revision-tracker)
 
 BOOTCYCLE_TARGET := product-images
 bootcycle-images:
@@ -329,13 +324,16 @@
 mac-bundles-jdk:
 	+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f MacBundles.gmk)
 
+release-file:
+	+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f ReleaseFile.gmk)
+
 exploded-image-optimize:
 	+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f ExplodedImageOptimize.gmk)
 
-ALL_TARGETS += source-tips create-hgtip-files bootcycle-images zip-security \
+ALL_TARGETS += store-source-revision create-source-revision-tracker bootcycle-images zip-security \
     zip-source jrtfs-jar jdk-image jre-image \
     symbols-image profiles mac-bundles-jdk \
-    exploded-image-optimize
+    release-file exploded-image-optimize
 
 ################################################################################
 # Docs targets
@@ -608,12 +606,12 @@
 
   jdk.jdeps-gendata: java rmic
 
-  # Declare dependencies between jmod targets. Only java.base jmod needs access
-  # to the other jmods to be built.
+  # Declare dependencies between jmod targets.
+  # java.base jmod needs jrt-fs.jar and access to the other jmods to be built.
   # When creating a BUILDJDK, we don't need to add hashes to java.base, thus
   # we don't need to depend on all other jmods
   ifneq ($(CREATING_BUILDJDK), true)
-    java.base-jmod: $(filter-out java.base-jmod \
+    java.base-jmod: jrtfs-jar $(filter-out java.base-jmod \
         $(addsuffix -jmod, $(call FindAllUpgradeableModules)), $(JMOD_TARGETS))
   endif
 
@@ -684,10 +682,12 @@
     java.base-jmod jdk-image jre-image: generate-link-opt-data
   endif
 
-  jdk-image: jmods zip-source source-tips demos samples jrtfs-jar
-  jre-image: jmods source-tips jrtfs-jar
+  release-file: create-source-revision-tracker
 
-  profiles: jmods zip-source source-tips jrtfs-jar
+  jdk-image: jmods zip-source demos samples release-file
+  jre-image: jmods release-file
+
+  profiles: jmods release-file
 
   mac-bundles-jdk: jdk-image jre-image
 
@@ -794,7 +794,7 @@
 
 # The "exploded image" is a locally runnable JDK in $(BUILD_OUTPUT)/jdk.
 exploded-image-base: $(ALL_MODULES)
-exploded-image: exploded-image-base
+exploded-image: exploded-image-base release-file
 # When cross compiling, no need to optimize the exploded image since it won't
 # be runnable on the host platform anyway.
 ifneq ($(COMPILE_TYPE), cross)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/ReleaseFile.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,86 @@
+#
+# 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.
+#
+
+default: all
+
+include $(SPEC)
+include MakeBase.gmk
+
+################################################################################
+# This makefile generates the "release" file into the exploded image. Jlink is
+# then responsible for using this as the base for release files in each linked
+# image.
+#
+################################################################################
+
+BASE_RELEASE_FILE := $(JDK_OUTPUTDIR)/release
+
+# Common way to emit a line into the release or info file
+define info-file-item # name value
+  $(PRINTF) '%s="%s"\n' $1 $2 >> $@
+endef
+
+# Param 1 - The file containing the MODULES list
+define create-info-file
+  $(if $(JDK_ARCH_ABI_PROP_NAME), \
+    $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)"))
+  $(call info-file-item, "SOURCE", "$(strip $(SOURCE_REVISION))")
+endef
+
+# Param 1 - The file containing the MODULES list
+define prepare-info-file
+  $(call LogInfo, Generating $(patsubst $(OUTPUT_ROOT)/%,%,$@))
+  $(call MakeDir, $(@D))
+  $(RM) $@
+endef
+
+define info-file
+  $(call prepare-info-file)
+  $(call create-info-file)
+endef
+
+# Create a variable dependency file common for all release info files.
+INFO_FILE_VARDEPS := $(call DependOnVariable, create-info-file)
+
+SOURCE_REVISION = $(shell \
+    if [ -f $(SOURCE_REVISION_TRACKER) ] ; then \
+      $(CAT) $(SOURCE_REVISION_TRACKER) ; \
+    fi)
+
+# The SOURCE_REVISION_TRACKER file may not exist. Only depend on it if it does.
+$(BASE_RELEASE_FILE): $(INFO_FILE_VARDEPS) $(wildcard $(SOURCE_REVISION_TRACKER))
+	$(info-file)
+
+TARGETS += $(BASE_RELEASE_FILE)
+
+################################################################################
+
+$(eval $(call IncludeCustomExtension, , ReleaseFile.gmk))
+
+################################################################################
+
+all: $(TARGETS)
+
+.PHONY: all default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/SourceRevision.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,131 @@
+#
+# 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.
+#
+
+default: all
+
+include $(SPEC)
+include MakeBase.gmk
+
+################################################################################
+# Keep track of what source revision is used to create the build, by creating
+# a tracker file in the output directory. This tracker file is included in the
+# image, and can be used to recreate the source revision used.
+#
+# We're either building directly from a mercurial forest, and if so, use the
+# current revision from mercurial. Otherwise, we are building from a source
+# bundle. As a part of creating this source bundle, the current mercurial
+# revisions of all repos will be stored in a file in the top dir, which is then
+# used when creating the tracker file.
+
+STORED_SOURCE_REVISION := $(TOPDIR)/.src-rev
+
+# Are we using mercurial?
+ifneq ($(and $(HG), $(wildcard $(TOPDIR)/.hg)), )
+
+  # Verify that the entire forest is consistent
+  $(foreach repo, $(call FindAllReposRel), \
+    $(if $(wildcard $(TOPDIR)/$(repo)/.hg),, \
+        $(error Inconsistent revision control: $(repo) is missing .hg directory)) \
+  )
+
+  # Replace "." with "_top" and "/" with "-"
+  MakeFilenameFromRepo = \
+      $(strip $(subst .,top, $(subst /,-, $1)))
+
+  ################################################################################
+  # SetupGetRevisionForRepo defines a make rule for creating a file containing
+  # the name of the repository and the output of "hg id" for that repository.
+  # Argument 1 is the relative path to the repository from the top dir.
+  #
+  SetupGetRevisionForRepo = $(NamedParamsMacroTemplate)
+  define SetupGetRevisionForRepoBody
+    $1_REPO_PATH :=  $$(TOPDIR)/$$(strip $1)
+    $1_FILENAME := $$(call MakeFilenameFromRepo, $1)
+
+    $$(SUPPORT_OUTPUTDIR)/src-rev/$$($1_FILENAME): FRC
+	$$(call MakeDir, $$(@D))
+	$$(ECHO) $$(strip $1):`$$(HG) id -i --repository $$($1_REPO_PATH)` > $$@
+
+    REPO_REVISIONS += $$(SUPPORT_OUTPUTDIR)/src-rev/$$($1_FILENAME)
+  endef
+
+  # Setup rules for all repos. This makes sure all the "hg id" calls are made
+  # in parallel.
+  $(foreach repo, $(call FindAllReposRel), \
+    $(eval $(call SetupGetRevisionForRepo, $(repo))) \
+  )
+
+  # Create a complete source revision output file from all repos
+  # Param 1: The output file
+  define CreateSourceRevisionFile
+    $1: $$(REPO_REVISIONS)
+	$$(call MakeDir, $$(@D))
+	$$(ECHO) `$$(CAT) $$(REPO_REVISIONS)` > $$@.tmp
+	if [ ! -f $$@ ] || [ "`$$(CAT) $$@`" != "`$$(CAT) $$@.tmp`" ]; then \
+	  $$(MV) $$@.tmp $$@ ; \
+	else \
+	  $$(RM) $$@.tmp ; \
+	fi
+  endef
+
+  $(eval $(call CreateSourceRevisionFile, $(STORED_SOURCE_REVISION)))
+
+  store-source-revision: $(STORED_SOURCE_REVISION)
+
+  $(eval $(call CreateSourceRevisionFile, $(SOURCE_REVISION_TRACKER)))
+
+  create-source-revision-tracker: $(SOURCE_REVISION_TRACKER)
+
+else
+  # Not using HG
+
+  ifneq ($(wildcard $(STORED_SOURCE_REVISION)), )
+    # We have a stored source revision (.src-rev)
+
+    store-source-revision:
+	$(call LogWarn, Warning: No mercurial configuration present, not updating .src-rev)
+
+    $(SOURCE_REVISION_TRACKER): $(STORED_SOURCE_REVISION)
+	$(install-file)
+
+    create-source-revision-tracker: $(SOURCE_REVISION_TRACKER)
+  else
+    # We don't have a stored source revision. Can't do anything, really.
+
+    store-source-revision:
+	$(call LogWarn, Error: No mercurial configuration present, cannot create .src-rev)
+	exit 2
+
+    create-source-revision-tracker:
+	$(call LogWarn, Warning: No mercurial configuration present and no .src-rev)
+  endif
+
+endif
+
+all: store-source-revision create-source-revision-tracker
+
+FRC: # Force target
+
+.PHONY: all store-source-revision create-source-revision-tracker
--- a/make/common/MakeBase.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/common/MakeBase.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -337,44 +337,21 @@
 endif # HAS_FILE_FUNCTION
 
 ################################################################################
-# The source tips can come from the Mercurial repository, or in the files
-# $(HGTIP_FILENAME) which contains the tip but is also positioned in the same
-# directory as the original .hg directory. The hgtip files are created in
-# CreateHgtipFiles.gmk.
-HGTIP_FILENAME := .hgtip
+
+# A file containing a way to uniquely identify the source code revision that
+# the build was created from
+SOURCE_REVISION_TRACKER := $(SUPPORT_OUTPUTDIR)/src-rev/source-revision-tracker
+
+# Locate all hg repositories included in the forest, as absolute paths
 FindAllReposAbs = \
     $(strip $(sort $(dir $(filter-out $(SRC_ROOT)/build/%, $(wildcard \
-        $(addprefix $(SRC_ROOT)/, \
-            .hg */.hg */*/.hg */*/.hg */*/*/.hg \
-            .hgtip */.hgtip */*/.hgtip */*/.hgtip */*/*/.hgtip \
-        ) \
+        $(addprefix $(SRC_ROOT)/, .hg */.hg */*/.hg */*/*/.hg) \
     )))))
 
+# Locate all hg repositories included in the forest, as relative paths
 FindAllReposRel = \
     $(strip $(subst $(SRC_ROOT)/,.,$(patsubst $(SRC_ROOT)/%/, %, $(FindAllReposAbs))))
 
-# Emit the repo:tip pairs to $@, but only if they changed since last time
-define GetSourceTips
-	$(CD) $(SRC_ROOT) ; \
-	for i in $(FindAllReposRel) IGNORE ; do \
-	  if [ "$${i}" = "IGNORE" ] ; then \
-	    continue; \
-	  elif [ -d $${i}/.hg -a "$(HG)" != "" ] ; then \
-	    $(PRINTF) " %s:%s" \
-	        "$${i}" `$(HG) tip --repository $${i} --template '{node|short}\n'` ; \
-	  elif [ -f $${i}/$(HGTIP_FILENAME) ] ; then \
-	    $(PRINTF) " %s:%s" \
-	        "$${i}" `$(CAT) $${i}/$(HGTIP_FILENAME)` ; \
-	  fi; \
-	done > $@.tmp
-	$(PRINTF) "\n" >> $@.tmp
-	if [ ! -f $@ ] || [ "`$(CAT) $@`" != "`$(CAT) $@.tmp`" ]; then \
-	  $(MV) $@.tmp $@ ; \
-	else \
-	  $(RM) $@.tmp ; \
-	fi
-endef
-
 ################################################################################
 
 define SetupLogging
--- a/make/common/Modules.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/common/Modules.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -171,12 +171,15 @@
 
 # Find all module-info.java files for the current build target platform and
 # configuration.
+# TODO: The $(firstword call is part of a workaround for using different
+# imported module-info.java in Jake due to a change in format. Remove once
+# new format is standard in JDK 9 and javafx delivers just that.
 # Param 1 - Module to find for, set to * for finding all
 FindAllModuleInfos = \
     $(wildcard \
         $(foreach sub, $(SRC_SUBDIRS), \
           $(patsubst %,%/$(strip $1)/$(sub)/module-info.java, $(TOP_SRC_DIRS))) \
-        $(patsubst %,%/$(strip $1)/module-info.java, $(IMPORT_MODULES_SRC)))
+        $(patsubst %,%/$(strip $1)/module-info.java, $(firstword $(IMPORT_MODULES_SRC))))
 
 # Find module-info.java files in the specific source dir
 # Param 1 - Src dir to find module-info.java files in
@@ -244,7 +247,7 @@
 	          BEGIN      { if (MODULE != "java.base") printf(" java.base"); } \
 	          /requires/ { sub(/;/, ""); \
 	                       sub(/requires/, ""); \
-	                       sub(/public/, ""); \
+	                       sub(/transitive/, ""); \
 	                       sub(/\/\/.*/, ""); \
 	                       sub(/\/\*.*\*\//, ""); \
 	                       gsub(/^ +\*.*/, ""); \
--- a/make/common/NativeCompilation.gmk	Fri Dec 02 10:52:51 2016 -0800
+++ b/make/common/NativeCompilation.gmk	Wed Jul 05 22:32:06 2017 +0200
@@ -568,17 +568,21 @@
   # Sort to remove dupliates and provide a reproducable order on the input files to the linker.
   $1_ALL_OBJS := $$(sort $$($1_EXPECTED_OBJS) $$($1_EXTRA_OBJECT_FILES))
 
-  # Pickup extra OPENJDK_TARGET_OS_TYPE and/or OPENJDK_TARGET_OS dependent variables for CFLAGS.
-  $1_EXTRA_CFLAGS:=$$($1_CFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_CFLAGS_$(OPENJDK_TARGET_OS))
+  # Pickup extra OPENJDK_TARGET_OS_TYPE, OPENJDK_TARGET_OS, and/or OPENJDK_TARGET_OS plus
+  # OPENJDK_TARGET_CPU pair dependent variables for CFLAGS.
+  $1_EXTRA_CFLAGS:=$$($1_CFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_CFLAGS_$(OPENJDK_TARGET_OS)) \
+      $$($1_CFLAGS_$(OPENJDK_TARGET_OS)_$(OPENJDK_TARGET_CPU))
   ifneq ($(DEBUG_LEVEL),release)
     # Pickup extra debug dependent variables for CFLAGS
     $1_EXTRA_CFLAGS+=$$($1_CFLAGS_debug)
     $1_EXTRA_CFLAGS+=$$($1_CFLAGS_$(OPENJDK_TARGET_OS_TYPE)_debug)
     $1_EXTRA_CFLAGS+=$$($1_CFLAGS_$(OPENJDK_TARGET_OS)_debug)
+    $1_EXTRA_CFLAGS+=$$($1_CFLAGS_$(OPENJDK_TARGET_OS)_$(OPENJDK_TARGET_CPU)_debug)
   else
     $1_EXTRA_CFLAGS+=$$($1_CFLAGS_release)
     $1_EXTRA_CFLAGS+=$$($1_CFLAGS_$(OPENJDK_TARGET_OS_TYPE)_release)
     $1_EXTRA_CFLAGS+=$$($1_CFLAGS_$(OPENJDK_TARGET_OS)_release)
+    $1_EXTRA_CFLAGS+=$$($1_CFLAGS_$(OPENJDK_TARGET_OS)_$(OPENJDK_TARGET_CPU)_release)
   endif
 
   # Pickup extra OPENJDK_TARGET_OS_TYPE and/or OPENJDK_TARGET_OS dependent variables for CXXFLAGS.
--- a/nashorn/.hgignore	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/.hgignore	Wed Jul 05 22:32:06 2017 +0200
@@ -1,6 +1,5 @@
 syntax: glob
 
-^.hgtip
 build/*
 dist/*
 /nbproject/private/
--- a/nashorn/.hgtags	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/.hgtags	Wed Jul 05 22:32:06 2017 +0200
@@ -380,3 +380,4 @@
 a7f21ee6ed30695a6de14e74035d2857a754f62b jdk-9+144
 4a68dd740be8aa0d1a25f94985b3cb2e190ccfce jdk-9+145
 55f5a96988de8237f3ee65a69aa4a48aed9ca8d4 jdk-9+146
+9e86d6383456a1eb0298c72bb9ca363939ad90cf jdk-9+147
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Wed Jul 05 22:32:06 2017 +0200
@@ -29,7 +29,6 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJ_PKG;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.RUNTIME_PKG;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTS_PKG;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_SYMBOL;
 
@@ -111,6 +110,8 @@
 
     private boolean isOptimistic;
 
+    private boolean convertsNumericArgs;
+
     /**
      * @return the kind
      */
@@ -172,6 +173,23 @@
     }
 
     /**
+     * Check if this function converts arguments for numeric parameters to numbers
+     * so it's safe to pass booleans as 0 and 1
+     * @return true if it is safe to convert arguments to numbers
+     */
+    public boolean convertsNumericArgs() {
+        return convertsNumericArgs;
+    }
+
+    /**
+     * Tag this as a function that converts arguments for numeric params to numbers
+     * @param convertsNumericArgs if true args can be safely converted to numbers
+     */
+    public void setConvertsNumericArgs(final boolean convertsNumericArgs) {
+        this.convertsNumericArgs = convertsNumericArgs;
+    }
+
+    /**
      * Get the SpecializedFunction guard for specializations, i.e. optimistic
      * builtins
      * @return specialization, null if none
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java	Wed Jul 05 22:32:06 2017 +0200
@@ -412,6 +412,7 @@
                 visitLdcInsn(linkLogicClass);
             }
             visitInsn(mi.isOptimistic() ? ICONST_1 : ICONST_0);
+            visitInsn(mi.convertsNumericArgs() ? ICONST_1 : ICONST_0);
             visitMethodInsn(INVOKESPECIAL, SPECIALIZATION_TYPE, INIT, ctor, false);
             arrayStore(TYPE_SPECIALIZATION);
         }
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Wed Jul 05 22:32:06 2017 +0200
@@ -210,6 +210,7 @@
                         private Where   where;
                         private boolean isSpecializedConstructor;
                         private boolean isOptimistic;
+                        private boolean convertsNumericArgs;
                         private Type    linkLogicClass = MethodGenerator.EMPTY_LINK_LOGIC_TYPE;
 
                         @Override
@@ -238,6 +239,10 @@
                             case "linkLogic":
                                 this.linkLogicClass = (Type)annotationValue;
                                 break;
+                            case "convertsNumericArgs":
+                                assert annoKind == Kind.SPECIALIZED_FUNCTION;
+                                this.convertsNumericArgs = (Boolean)annotationValue;
+                                break;
                             default:
                                 break;
                             }
@@ -298,6 +303,7 @@
                             memInfo.setLinkLogicClass(linkLogicClass);
                             memInfo.setIsSpecializedConstructor(isSpecializedConstructor);
                             memInfo.setIsOptimistic(isOptimistic);
+                            memInfo.setConvertsNumericArgs(convertsNumericArgs);
                         }
                     };
                 }
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Wed Jul 05 22:32:06 2017 +0200
@@ -45,7 +45,6 @@
 
     // standard jdk types, methods
     static final Type TYPE_METHODHANDLE         = Type.getType(MethodHandle.class);
-    static final Type TYPE_METHODHANDLE_ARRAY   = Type.getType(MethodHandle[].class);
     static final Type TYPE_SPECIALIZATION       = Type.getType("L" + RUNTIME_PKG + "Specialization;");
     static final Type TYPE_SPECIALIZATION_ARRAY = Type.getType("[L" + RUNTIME_PKG + "Specialization;");
     static final Type TYPE_OBJECT               = Type.getType(Object.class);
@@ -60,13 +59,11 @@
     static final String INIT = "<init>";
     static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE);
 
-    static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName();
     static final String SPECIALIZATION_TYPE = TYPE_SPECIALIZATION.getInternalName();
-    static final String SPECIALIZATION_INIT2 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, Type.getType(boolean.class));
-    static final String SPECIALIZATION_INIT3 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, TYPE_CLASS, Type.getType(boolean.class));
+    static final String SPECIALIZATION_INIT2 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE);
+    static final String SPECIALIZATION_INIT3 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, TYPE_CLASS, Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE);
     static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName();
     static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor();
-    static final String STRING_TYPE = TYPE_STRING.getInternalName();
     static final String STRING_DESC = TYPE_STRING.getDescriptor();
     static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class);
     static final String ARRAYLIST_TYPE = TYPE_ARRAYLIST.getInternalName();
--- a/nashorn/make/build.xml	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/make/build.xml	Wed Jul 05 22:32:06 2017 +0200
@@ -28,6 +28,10 @@
   <import file="code_coverage.xml"/>
 
   <target name="load-properties">
+    <!-- set default values to run.test.jvmargs.external property -->
+    <condition property="run.test.jvmargs.external" value="">
+     <not><isset property="run.test.jvmargs.external"/></not>
+    </condition>     
     <!-- loading locally defined resources and properties. NB they owerwrite default ones defined later -->
     <property file="${user.home}/.nashorn.project.local.properties"/>
 
--- a/nashorn/make/project.properties	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/make/project.properties	Wed Jul 05 22:32:06 2017 +0200
@@ -154,7 +154,9 @@
     --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp=ALL-UNNAMED \
     --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp.joni=ALL-UNNAMED \
     --add-exports jdk.scripting.nashorn/jdk.nashorn.tools=ALL-UNNAMED \
-    --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
+    --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
+    --add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime=ALL-UNNAMED \
+    --add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv=ALL-UNNAMED
 
 meta.inf.dir=${nashorn.module.src.dir}/META-INF
 
@@ -353,6 +355,7 @@
 run.test.jvmargs.common=\
   -server \
   ${test.module.imports} \
+  ${run.test.jvmargs.external} \
   ${nashorn.override.option} \
   -Dfile.encoding=UTF-8 \
   -Duser.language=${run.test.user.language} \
--- a/nashorn/src/jdk.dynalink/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.dynalink/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Dynalink
+ */
 module jdk.dynalink {
     requires java.logging;
 
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Nashorn shell module
+ */
 module jdk.scripting.nashorn.shell {
     requires java.desktop;
     requires java.compiler;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java	Wed Jul 05 22:32:06 2017 +0200
@@ -244,7 +244,7 @@
      * @param global the global
      * @return initialized exception
      */
-    protected NashornException initEcmaError(final ScriptObject global) {
+    NashornException initEcmaError(final ScriptObject global) {
         if (ecmaError != null) {
             return this; // initialized already!
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Jul 05 22:32:06 2017 +0200
@@ -4066,7 +4066,7 @@
                     void loadStack() {
                         assert assignNode.getWidestOperandType() == Type.INT;
                         if (isRhsZero(binaryNode)) {
-                            loadExpressionAsType(binaryNode.lhs(), Type.INT);
+                            loadExpression(binaryNode.lhs(), TypeBounds.INT, true);
                         } else {
                             loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.INT, true, false);
                             method.shr();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Wed Jul 05 22:32:06 2017 +0200
@@ -61,7 +61,6 @@
 import jdk.nashorn.internal.runtime.OptimisticBuiltins;
 import jdk.nashorn.internal.runtime.PropertyDescriptor;
 import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.Undefined;
@@ -748,7 +747,7 @@
      * @param arg argument
      * @return resulting NativeArray
      */
-    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class, convertsNumericArgs = false)
     public static NativeArray concat(final Object self, final int arg) {
         final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Integer.class).copy(); //get at least an integer data copy of this data
         newData.fastPush(arg); //add an integer to its end
@@ -762,21 +761,7 @@
      * @param arg argument
      * @return resulting NativeArray
      */
-    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
-    public static NativeArray concat(final Object self, final long arg) {
-        final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Long.class).copy(); //get at least a long array data copy of this data
-        newData.fastPush(arg); //add a long at the end
-        return new NativeArray(newData);
-    }
-
-    /**
-     * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
-     *
-     * @param self self reference
-     * @param arg argument
-     * @return resulting NativeArray
-     */
-    @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+    @SpecializedFunction(linkLogic=ConcatLinkLogic.class, convertsNumericArgs = false)
     public static NativeArray concat(final Object self, final double arg) {
         final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Double.class).copy(); //get at least a number array data copy of this data
         newData.fastPush(arg); //add a double at the end
@@ -837,13 +822,12 @@
     private static void concatToList(final ArrayList<Object> list, final Object obj) {
         final boolean isScriptArray  = isArray(obj);
         final boolean isScriptObject = isScriptArray || obj instanceof ScriptObject;
-        if (isScriptArray || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) {
+        if (isScriptArray || obj instanceof Iterable || obj instanceof JSObject || (obj != null && obj.getClass().isArray())) {
             final Iterator<Object> iter = arrayLikeIterator(obj, true);
             if (iter.hasNext()) {
                 for (int i = 0; iter.hasNext(); ++i) {
                     final Object value = iter.next();
-                    final boolean lacksIndex = obj != null && !((ScriptObject)obj).has(i);
-                    if (value == ScriptRuntime.UNDEFINED && isScriptObject && lacksIndex) {
+                    if (value == ScriptRuntime.UNDEFINED && isScriptObject && !((ScriptObject)obj).has(i)) {
                         // TODO: eventually rewrite arrayLikeIterator to use a three-state enum for handling
                         // UNDEFINED instead of an "includeUndefined" boolean with states SKIP, INCLUDE,
                         // RETURN_EMPTY. Until then, this is how we'll make sure that empty elements don't make it
@@ -980,7 +964,7 @@
      * @param arg a primitive to push
      * @return array length after push
      */
-    @SpecializedFunction(linkLogic=PushLinkLogic.class)
+    @SpecializedFunction(linkLogic=PushLinkLogic.class, convertsNumericArgs = false)
     public static double push(final Object self, final int arg) {
         return getContinuousArrayDataCCE(self, Integer.class).fastPush(arg);
     }
@@ -994,21 +978,7 @@
      * @param arg a primitive to push
      * @return array length after push
      */
-    @SpecializedFunction(linkLogic=PushLinkLogic.class)
-    public static double push(final Object self, final long arg) {
-        return getContinuousArrayDataCCE(self, Long.class).fastPush(arg);
-    }
-
-    /**
-     * ECMA 15.4.4.7 Array.prototype.push (args...)
-     *
-     * Primitive specialization, {@link LinkLogic}
-     *
-     * @param self self reference
-     * @param arg a primitive to push
-     * @return array length after push
-     */
-    @SpecializedFunction(linkLogic=PushLinkLogic.class)
+    @SpecializedFunction(linkLogic=PushLinkLogic.class, convertsNumericArgs = false)
     public static double push(final Object self, final double arg) {
         return getContinuousArrayDataCCE(self, Double.class).fastPush(arg);
     }
@@ -1857,15 +1827,14 @@
             }
 
             final Object arg = args[2];
-            //args[2] continuousarray or non arraydata, let past non array datas
+            // The generic version uses its own logic and ArrayLikeIterator to decide if an object should
+            // be iterated over or added as single element. To avoid duplication of code and err on the safe side
+            // we only use the specialized version if arg is either a continuous array or a JS primitive.
             if (arg instanceof NativeArray) {
-                final ContinuousArrayData argData = getContinuousArrayData(arg);
-                if (argData == null) {
-                    return false;
-                }
+                return (getContinuousArrayData(arg) != null);
             }
 
-            return true;
+            return JSType.isPrimitive(arg);
         }
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java	Wed Jul 05 22:32:06 2017 +0200
@@ -539,17 +539,6 @@
     }
 
     /**
-     * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for long position
-     * @param self self reference
-     * @param pos  position in string
-     * @return number representing charcode at position
-     */
-    @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
-    public static int charCodeAt(final Object self, final long pos) {
-        return charCodeAt(self, (int)pos);
-    }
-
-    /**
      * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for int position
      * @param self self reference
      * @param pos  position in string
@@ -1176,24 +1165,7 @@
     }
 
     /**
-     * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
-     *
-     * Constructor
-     *
-     * @param newObj is this constructor invoked with the new operator
-     * @param self   self reference
-     * @param arg    the arg
-     *
-     * @return new NativeString containing the string representation of the arg
-     */
-    @SpecializedFunction(isConstructor=true)
-    public static Object constructor(final boolean newObj, final Object self, final long arg) {
-        final String str = Long.toString(arg);
-        return newObj ? newObj(str) : str;
-    }
-
-    /**
-     * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
+     * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code double} arg
      *
      * Constructor
      *
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java	Wed Jul 05 22:32:06 2017 +0200
@@ -215,4 +215,14 @@
      * @return whether this function can throw {@link UnwarrantedOptimismException}.
      */
     boolean isOptimistic() default false;
+
+    /**
+     * Is it safe to convert non-numeric arguments to numbers for this function's primitive numeric parameters?
+     * This is true for many built-in functions which expect numeric arguments, but not for those that
+     * expect generic arguments and just have specializations with numeric params to avoid boxing overhead.
+     * The default value is {@code true} because that is by far the most common case.
+     *
+     * @return true if it is safe to convert arguments to numbers
+     */
+    boolean convertsNumericArgs() default true;
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed Jul 05 22:32:06 2017 +0200
@@ -152,6 +152,10 @@
         return null;
     }
 
+    boolean convertsNumericArgs() {
+        return isSpecialization() && specialization.convertsNumericArgs();
+    }
+
     int getFlags() {
         return flags;
     }
@@ -388,10 +392,18 @@
             int narrowWeightDelta = 0;
             int widenWeightDelta = 0;
             final int minParamsCount = Math.min(Math.min(thisParamCount, otherParamCount), callSiteParamCount);
+            final boolean convertsNumericArgs = cf.convertsNumericArgs();
             for(int i = 0; i < minParamsCount; ++i) {
-                final int callSiteParamWeight = getParamType(i, callSiteType, csVarArg).getWeight();
+                final Type callSiteParamType = getParamType(i, callSiteType, csVarArg);
+                final Type thisParamType = getParamType(i, thisType, thisVarArg);
+                if (!convertsNumericArgs && callSiteParamType.isBoolean() && thisParamType.isNumeric()) {
+                    // When an argument is converted to number by a function it is safe to "widen" booleans to numeric types.
+                    // However, we must avoid this conversion for generic functions such as Array.prototype.push.
+                    return false;
+                }
+                final int callSiteParamWeight = callSiteParamType.getWeight();
                 // Delta is negative for narrowing, positive for widening
-                final int thisParamWeightDelta = getParamType(i, thisType, thisVarArg).getWeight() - callSiteParamWeight;
+                final int thisParamWeightDelta = thisParamType.getWeight() - callSiteParamWeight;
                 final int otherParamWeightDelta = getParamType(i, otherType, otherVarArg).getWeight() - callSiteParamWeight;
                 // Only count absolute values of narrowings
                 narrowWeightDelta += Math.max(-thisParamWeightDelta, 0) - Math.max(-otherParamWeightDelta, 0);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Wed Jul 05 22:32:06 2017 +0200
@@ -320,7 +320,7 @@
     private final WeakValueCache<CodeSource, Class<?>> anonymousHostClasses = new WeakValueCache<>();
 
     private static final class AnonymousContextCodeInstaller extends ContextCodeInstaller {
-        private static final Unsafe UNSAFE = getUnsafe();
+        private static final Unsafe UNSAFE = Unsafe.getUnsafe();
         private static final String ANONYMOUS_HOST_CLASS_NAME = Compiler.SCRIPTS_PACKAGE.replace('/', '.') + ".AnonymousHost";
         private static final byte[] ANONYMOUS_HOST_CLASS_BYTES = getAnonymousHostClassBytes();
 
@@ -357,21 +357,6 @@
             cw.visitEnd();
             return cw.toByteArray();
         }
-
-        private static Unsafe getUnsafe() {
-            return AccessController.doPrivileged(new PrivilegedAction<Unsafe>() {
-                @Override
-                public Unsafe run() {
-                    try {
-                        final Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
-                        theUnsafeField.setAccessible(true);
-                        return (Unsafe)theUnsafeField.get(null);
-                    } catch (final ReflectiveOperationException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            });
-        }
     }
 
     /** Is Context global debug mode enabled ? */
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptLoader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptLoader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -69,12 +69,12 @@
     private Module createModule(final String moduleName) {
         final Module structMod = context.getStructLoader().getModule();
         final ModuleDescriptor.Builder builder =
-            new ModuleDescriptor.Builder(moduleName)
+            ModuleDescriptor.module(moduleName)
                     .requires("java.base")
                     .requires("java.logging")
                     .requires(NASHORN_MODULE.getName())
                     .requires(structMod.getName())
-                    .conceals(SCRIPTS_PKG);
+                    .contains(SCRIPTS_PKG);
 
         if (Context.javaSqlFound) {
             builder.requires("java.sql");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Specialization.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Specialization.java	Wed Jul 05 22:32:06 2017 +0200
@@ -36,6 +36,7 @@
     private final MethodHandle mh;
     private final Class<? extends LinkLogic> linkLogicClass;
     private final boolean isOptimistic;
+    private final boolean convertsNumericArgs;
 
     /**
      * Constructor
@@ -43,7 +44,7 @@
      * @param mh  invoker method handler
      */
     public Specialization(final MethodHandle mh) {
-        this(mh, false);
+        this(mh, false, true);
     }
 
     /**
@@ -52,9 +53,10 @@
      * @param mh  invoker method handler
      * @param isOptimistic is this an optimistic native method, i.e. can it throw {@link UnwarrantedOptimismException}
      *   which would have to lead to a relink and return value processing
+     * @param convertsNumericArgs true if it is safe to convert arguments to numbers
      */
-    public Specialization(final MethodHandle mh, final boolean isOptimistic) {
-        this(mh, null, isOptimistic);
+    public Specialization(final MethodHandle mh, final boolean isOptimistic, final boolean convertsNumericArgs) {
+        this(mh, null, isOptimistic, convertsNumericArgs);
     }
 
     /**
@@ -65,10 +67,13 @@
      *  if this can be linked on its first encounter, which is needed as per our standard linker semantics
      * @param isOptimistic is this an optimistic native method, i.e. can it throw {@link UnwarrantedOptimismException}
      *   which would have to lead to a relink and return value processing
+     * @param convertsNumericArgs true if it is safe to convert arguments to numbers
      */
-    public Specialization(final MethodHandle mh, final Class<? extends LinkLogic> linkLogicClass, final boolean isOptimistic) {
+    public Specialization(final MethodHandle mh, final Class<? extends LinkLogic> linkLogicClass,
+                          final boolean isOptimistic, final boolean convertsNumericArgs) {
         this.mh             = mh;
         this.isOptimistic   = isOptimistic;
+        this.convertsNumericArgs = convertsNumericArgs;
         if (linkLogicClass != null) {
             //null out the "empty" link logic class for optimization purposes
             //we only use the empty instance because we can't default class annotations
@@ -110,5 +115,15 @@
         return isOptimistic;
     }
 
+    /**
+     * Check if this function converts arguments for numeric parameters to numbers
+     * so it's safe to pass booleans as 0 and 1
+     *
+     * @return true if it is safe to convert arguments to numbers
+     */
+    public boolean convertsNumericArgs() {
+        return convertsNumericArgs;
+    }
+
 }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/StructureLoader.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/StructureLoader.java	Wed Jul 05 22:32:06 2017 +0200
@@ -63,10 +63,10 @@
 
     private Module createModule(final String moduleName) {
         final ModuleDescriptor descriptor
-                = new ModuleDescriptor.Builder(moduleName)
+                = ModuleDescriptor.module(moduleName)
                     .requires("java.base")
                     .requires(NASHORN_MODULE.getName())
-                    .conceals(SCRIPTS_PKG)
+                    .contains(SCRIPTS_PKG)
                     .build();
 
         final Module mod = Context.createModuleTrusted(descriptor, this);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Wed Jul 05 22:32:06 2017 +0200
@@ -40,9 +40,13 @@
 import jdk.dynalink.linker.LinkerServices;
 import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
 import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.objects.Global;
 
 /**
  * A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well
@@ -142,9 +146,9 @@
     }
 
     private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
-        MethodHandle mh = JSOBJECT_CALL;
+        MethodHandle mh = NashornCallSiteDescriptor.isScope(desc)? JSOBJECT_SCOPE_CALL : JSOBJECT_CALL;
         if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
-            mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, JSOBJECT_CALL);
+            mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, mh);
         }
         final MethodType type = desc.getMethodType();
         mh = type.parameterType(type.parameterCount() - 1) == Object[].class ?
@@ -215,6 +219,19 @@
         }
     }
 
+    // This is used when a JSObject is called as scope call to do undefined -> Global this translation.
+    @SuppressWarnings("unused")
+    private static Object jsObjectScopeCall(final JSObject jsObj, final Object thiz, final Object[] args) {
+        final Object modifiedThiz;
+        if (thiz == ScriptRuntime.UNDEFINED && !jsObj.isStrictFunction()) {
+            final Global global = Context.getGlobal();
+            modifiedThiz = ScriptObjectMirror.wrap(global, global);
+        } else {
+            modifiedThiz = thiz;
+        }
+        return jsObj.call(modifiedThiz, args);
+    }
+
     private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
 
     // method handles of the current class
@@ -226,6 +243,7 @@
     private static final MethodHandle JSOBJECT_GETMEMBER     = findJSObjectMH_V("getMember", Object.class, String.class);
     private static final MethodHandle JSOBJECT_SETMEMBER     = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class);
     private static final MethodHandle JSOBJECT_CALL          = findJSObjectMH_V("call", Object.class, Object.class, Object[].class);
+    private static final MethodHandle JSOBJECT_SCOPE_CALL    = findOwnMH_S("jsObjectScopeCall", Object.class, JSObject.class, Object.class, Object[].class);
     private static final MethodHandle JSOBJECT_CALL_TO_APPLY = findOwnMH_S("callToApply", Object.class, MethodHandle.class, JSObject.class, Object.class, Object[].class);
     private static final MethodHandle JSOBJECT_NEW           = findJSObjectMH_V("newObject", Object.class, Object[].class);
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/scripts/ModuleGraphManipulator.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/scripts/ModuleGraphManipulator.java	Wed Jul 05 22:32:06 2017 +0200
@@ -61,8 +61,8 @@
             throw new IllegalStateException(myClass + " loaded by wrong loader!");
         }
 
-        // From this module add a qualified export to nashorn module
-        MY_MODULE.addExports(MY_PKG_NAME, nashornModule);
+        // open package to nashorn module
+        MY_MODULE.addOpens(MY_PKG_NAME, nashornModule);
     }
 
     // The following method is reflectively invoked from Nashorn
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/module-info.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/module-info.java	Wed Jul 05 22:32:06 2017 +0200
@@ -23,9 +23,12 @@
  * questions.
  */
 
+/**
+ * Nashorn
+ */
 module jdk.scripting.nashorn {
     requires java.logging;
-    requires public java.scripting;
+    requires transitive java.scripting;
     requires jdk.dynalink;
 
     exports jdk.nashorn.api.scripting;
--- a/nashorn/test/TEST.ROOT	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/test/TEST.ROOT	Wed Jul 05 22:32:06 2017 +0200
@@ -8,7 +8,7 @@
 groups=TEST.groups
 
 # Minimum jtreg version
-requiredVersion=4.2 b03
+requiredVersion=4.2 b04
 
 # Use new module options
 useNewOptions=true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8161579.js	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8161579: Array-like AbstractJSObject-based instance not treated as array by native array functions
+ *
+ * @test
+ * @run
+ */
+
+
+var AbstractJSObject = Java.type("jdk.nashorn.api.scripting.AbstractJSObject");
+var JavaStringArray = Java.type("java.lang.String[]");
+var JavaArrayList = Java.type("java.util.ArrayList");
+
+var arrayLikeJSObject = new AbstractJSObject() {
+    hasMember: function(name) { return name == "length"; },
+    getMember: function(name) { return name == "length" ? 3 : null; },
+    hasSlot: function(slot) { return slot >= 0 && slot <= 2; },
+    getSlot: function(slot) { return "abc"[slot]; },
+    isArray: function() { return true; }
+}
+
+var javaStringArray = new JavaStringArray(3);
+javaStringArray[0] = "x";
+javaStringArray[1] = "y";
+javaStringArray[2] = "z";
+
+var javaArrayList = new JavaArrayList();
+javaArrayList.add("i");
+javaArrayList.add("j");
+javaArrayList.add("k");
+
+Assert.assertEquals([1, 2, 3].concat(arrayLikeJSObject).join(), "1,2,3,a,b,c");
+Assert.assertEquals([1, 2, 3].concat(javaStringArray).join(), "1,2,3,x,y,z");
+Assert.assertEquals([1, 2, 3].concat(javaArrayList).join(), "1,2,3,i,j,k");
+Assert.assertEquals([1, 2, 3].concat("foo").join(), "1,2,3,foo");
+Assert.assertEquals([1, 2, 3].concat(4).join(), "1,2,3,4");
+Assert.assertEquals([1, 2, 3].concat(false).join(), "1,2,3,false");
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8170322.js	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8170322: Specialized functions convert booleans to numbers
+ *
+ * @test
+ * @run
+ */
+
+var array = [];
+array.push(true);
+array.push(false);
+
+Assert.assertTrue([].concat(true)[0] === true);
+Assert.assertTrue([].concat(false)[0] === false);
+
+Assert.assertTrue(array[0] === true);
+Assert.assertTrue(array[1] === false);
+
+Assert.assertTrue("foo".charAt(false) === 'f');
+Assert.assertTrue("foo".charAt(true) === 'o');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8170594.js	Wed Jul 05 22:32:06 2017 +0200
@@ -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.
+ */
+
+/**
+ * JDK-8170594: >>>=0 generates invalid bytecode for BaseNode LHS
+ *
+ * @test
+ * @run
+ */
+
+var obj1 = {x: "100"};
+(function (o, p) {
+ if (p) {
+   o.x >>>= 0;
+ }
+})(obj1, true)
+Assert.assertTrue(obj1.x === 100)
+
+var obj2 = ["100"];
+(function (o, p) {
+ if (p) {
+   o[0] >>>= 0;
+ }
+})(obj2, true)
+Assert.assertTrue(obj2[0] === 100)
--- a/nashorn/test/script/currently-failing/JDK-8130127.js	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * JDK-8130127: streamline input parameter of Nashorn scripting $EXEC function
- *
- * Test different variants of stdin passing to $EXEC.
- *
- * @test
- * @option -scripting
- * @run
- */
-
-var File = java.io.File,
-    sep = File.separator,
-    System = java.lang.System,
-    os = System.getProperty("os.name"),
-    win = os.startsWith("Windows"),
-    jjsName = "jjs" + (win ? ".exe" : ""),
-    javaHome = System.getProperty("java.home")
-
-var jjs = javaHome + "/../bin/".replace(/\//g, sep) + jjsName
-if (!new File(jjs).isFile()) {
-    jjs = javaHome + "/bin/".replace(/\//g, sep) + jjsName
-}
-
-var jjsCmd = jjs + " readprint.js"
-
-print($EXEC(jjsCmd))
-print($EXEC(jjsCmd, null))
-print($EXEC(jjsCmd, undefined))
-print($EXEC(jjsCmd, ""))
-
-print($EXEC(jjs, "print('hello')"))
-
--- a/nashorn/test/script/currently-failing/JDK-8130127.js.EXPECTED	Fri Dec 02 10:52:51 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-
-
-
-
-hello
-
--- a/nashorn/test/script/nosecurity/JDK-8044798.js	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/test/script/nosecurity/JDK-8044798.js	Wed Jul 05 22:32:06 2017 +0200
@@ -33,13 +33,14 @@
 
 var Arrays = Java.type("java.util.Arrays");
 var CharArray = Java.type("char[]");
+var Reflector = Java.type("jdk.nashorn.test.models.Reflector");
 var DebuggerSupport = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport");
 var DebuggerValueDesc = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport.DebuggerValueDesc");
 
 var valueDescFields = DebuggerValueDesc.class.declaredFields;
 Arrays.sort(valueDescFields, function(f1, f2) f1.name.compareTo(f2.name));
 for each (var f in valueDescFields) {
-    f.accessible = true;
+    Reflector.setAccessible(f);
 }
 
 var debuggerSupportMethods = DebuggerSupport.class.declaredMethods;
@@ -49,7 +50,7 @@
 var getSourceInfoMethod, valueAsStringMethod;
 
 for each (var m in debuggerSupportMethods) {
-    m.accessible = true;
+    Reflector.setAccessible(m);
     switch (m.name) {
         case "eval":
             evalMethod = m;
@@ -129,10 +130,10 @@
 // private compile method of Context class
 var compileMethod = contextCls.getDeclaredMethod("compile",
                 sourceCls, errorMgrCls, booleanCls, booleanCls);
-compileMethod.accessible = true;
+Reflector.setAccessible(compileMethod);
 
 var getContextMethod = contextCls.getMethod("getContext");
-getContextMethod.accessible = true;
+Reflector.setAccessible(getContextMethod);
 
 var sourceForMethod = sourceCls.getMethod("sourceFor", stringCls, stringCls);
 var scriptCls = compileMethod.invoke(getContextMethod.invoke(null),
@@ -149,7 +150,7 @@
 
 print("Source info");
 for each (var f in srcInfoFields) {
-    f.accessible = true;
+    Reflector.setAccessible(f);
     var fieldValue = f.get(srcInfo);
     if (fieldValue instanceof CharArray) {
         fieldValue = new java.lang.String(fieldValue);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/JDK-8130127.js	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+/**
+ * JDK-8130127: streamline input parameter of Nashorn scripting $EXEC function
+ *
+ * Test different variants of stdin passing to $EXEC.
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+var File = java.io.File,
+    sep = File.separator,
+    System = java.lang.System,
+    os = System.getProperty("os.name"),
+    win = os.startsWith("Windows"),
+    jjsName = "jjs" + (win ? ".exe" : ""),
+    javaHome = System.getProperty("java.home")
+
+var jjs = javaHome + "/../bin/".replace(/\//g, sep) + jjsName
+if (!new File(jjs).isFile()) {
+    jjs = javaHome + "/bin/".replace(/\//g, sep) + jjsName
+}
+
+var jjsCmd = jjs + " readprint.js"
+
+print($EXEC(jjsCmd))
+print($EXEC(jjsCmd, null))
+print($EXEC(jjsCmd, undefined))
+print($EXEC(jjsCmd, ""))
+
+print($EXEC(jjs, "print('hello')\n"))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/JDK-8130127.js.EXPECTED	Wed Jul 05 22:32:06 2017 +0200
@@ -0,0 +1,7 @@
+
+
+
+
+jjs> print('hello')
+hello
+jjs> 
--- a/nashorn/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -41,6 +41,7 @@
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
+import jdk.nashorn.api.scripting.AbstractJSObject;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import org.testng.annotations.Test;
@@ -389,4 +390,41 @@
         assertTrue(func.isFunction());
         assertEquals(func.call(e.eval("this"), "hello"), "hello world");
     }
+
+    // @bug 8170565: JSObject call() is passed undefined for the argument 'thiz'
+    @Test
+    public void jsObjectThisTest() throws Exception {
+        final ScriptEngineManager engineManager = new ScriptEngineManager();
+        final ScriptEngine e = engineManager.getEngineByName("nashorn");
+        e.put("func", new AbstractJSObject() {
+            @Override
+            public boolean isFunction() { return true; }
+
+            @Override
+            public Object call(Object thiz, Object...args) {
+                return thiz;
+            }
+        });
+
+        assertTrue((boolean)e.eval("func() === this"));
+
+        // check that there is no blind undefined->Global translation!
+        assertTrue((boolean)e.eval("typeof(Function.prototype.call.call(func, undefined)) == 'undefined'"));
+
+        // make sure that strict functions don't get translated this for scope calls!
+        e.put("sfunc", new AbstractJSObject() {
+            @Override
+            public boolean isFunction() { return true; }
+
+            @Override
+            public boolean isStrictFunction() { return true; }
+
+            @Override
+            public Object call(Object thiz, Object...args) {
+                return thiz;
+            }
+        });
+
+        assertTrue((boolean)e.eval("typeof sfunc() == 'undefined'"));
+    }
 }
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/doubleconv/test/BignumTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/doubleconv/test/BignumTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -69,7 +69,7 @@
  * Bignum class tests
  *
  * @test
- * @modules jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv
+ * @modules jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv:open
  * @run testng jdk.nashorn.internal.runtime.doubleconv.test.BignumTest
  */
 @SuppressWarnings("javadoc")
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/doubleconv/test/DiyFpTest.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/doubleconv/test/DiyFpTest.java	Wed Jul 05 22:32:06 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -44,7 +44,7 @@
  * DiyFp class tests
  *
  * @test
- * @modules jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv
+ * @modules jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv:open
  * @run testng jdk.nashorn.internal.runtime.doubleconv.test.DiyFpTest
  */
 @SuppressWarnings("javadoc")
--- a/nashorn/test/src/jdk/nashorn/test/models/Reflector.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/nashorn/test/src/jdk/nashorn/test/models/Reflector.java	Wed Jul 05 22:32:06 2017 +0200
@@ -26,6 +26,7 @@
 package jdk.nashorn.test.models;
 
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Module;
@@ -42,6 +43,22 @@
     private Reflector() {}
     private static final Module NASHORN_MOD = Context.class.getModule();
 
+    public static void setAccessible(Executable e) {
+        if (e.getDeclaringClass().getModule() != NASHORN_MOD) {
+            throw new RuntimeException(e + " is not from Nashorn module");
+        }
+
+        e.setAccessible(true);
+    }
+
+    public static void setAccessible(Field f) {
+        if (f.getDeclaringClass().getModule() != NASHORN_MOD) {
+            throw new RuntimeException(f + " is not from Nashorn module");
+        }
+
+        f.setAccessible(true);
+    }
+
     public static Object invoke(final Method m, final Object self, final Object...args) {
         if (m.getDeclaringClass().getModule() != NASHORN_MOD) {
             throw new RuntimeException(m + " is not from Nashorn module");
--- a/test/lib/sun/hotspot/WhiteBox.java	Fri Dec 02 10:52:51 2016 -0800
+++ b/test/lib/sun/hotspot/WhiteBox.java	Wed Jul 05 22:32:06 2017 +0200
@@ -453,8 +453,6 @@
                                   Object[] packages);
   public native void AddModuleExports(Object from_module, String pkg, Object to_module);
   public native void AddReadsModule(Object from_module, Object source_module);
-  public native boolean CanReadModule(Object asking_module, Object source_module);
-  public native boolean IsExportedToModule(Object from_module, String pkg, Object to_module);
   public native void AddModulePackage(Object module, String pkg);
   public native void AddModuleExportsToAllUnnamed(Object module, String pkg);
   public native void AddModuleExportsToAll(Object module, String pkg);