changeset 42939:e5d5f0f2d40d

Merge
author prr
date Mon, 19 Dec 2016 09:16:40 -0800
parents c0b3077af726 8ea2f3d10b8c
children 0d1409532a41
files jdk/make/copy/Copy-jdk.crypto.pkcs11.gmk jdk/make/launcher/Launcher-jdk.pack200.gmk jdk/make/lib/Lib-jdk.crypto.pkcs11.gmk jdk/make/lib/Lib-jdk.pack200.gmk jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java jdk/src/java.base/share/classes/java/lang/module/ModulePath.java jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java jdk/src/java.compact1/share/classes/module-info.java jdk/src/java.compact2/share/classes/module-info.java jdk/src/java.compact3/share/classes/module-info.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNBindingEnumeration.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtx.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNCtxFactory.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CNNameParser.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/CorbanameUrl.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/ExceptionMapper.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/IiopUrl.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/OrbReuseTracker.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/RemoteToCorba.java jdk/src/java.corba/share/classes/com/sun/jndi/cosnaming/jndiprovider.properties jdk/src/java.corba/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java jdk/src/java.corba/share/classes/com/sun/jndi/url/corbaname/corbanameURLContextFactory.java jdk/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContext.java jdk/src/java.corba/share/classes/com/sun/jndi/url/iiop/iiopURLContextFactory.java jdk/src/java.corba/share/classes/com/sun/jndi/url/iiopname/iiopnameURLContextFactory.java jdk/src/jdk.crypto.pkcs11/share/classes/module-info.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Config.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/KeyCache.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11DHKeyFactory.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Digest.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11ECKeyFactory.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Key.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyAgreement.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyFactory.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyGenerator.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyStore.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Mac.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11RSACipher.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11SecureRandom.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Signature.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Util.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Secmod.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Session.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SessionManager.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/TemplateManager.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Token.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ATTRIBUTE.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_CREATEMUTEX.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_C_INITIALIZE_ARGS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_DATE.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_DESTROYMUTEX.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_ECDH2_DERIVE_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_INFO.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_LOCKMUTEX.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM_INFO.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_NOTIFY.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SESSION_INFO.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SLOT_INFO.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_MASTER_KEY_DERIVE_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_TOKEN_INFO.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_UNLOCKMUTEX.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_VERSION.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH2_DERIVE_PARAMS.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/Constants.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/Functions.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/PKCS11RuntimeException.java jdk/src/jdk.crypto.pkcs11/share/legal/pkcs11cryptotoken.md jdk/src/jdk.crypto.pkcs11/share/legal/pkcs11wrapper.md jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/j2secmod.h jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_convert.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_crypt.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_digest.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_dual.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_general.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_keymgmt.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_mutex.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_objmgmt.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sessmgmt.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_sign.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/p11_util.c jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs-11v2-20a3.h jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11.h jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11f.h jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11t.h jdk/src/jdk.crypto.pkcs11/share/native/libj2pkcs11/pkcs11wrapper.h jdk/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.c jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/j2secmod_md.h jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.c jdk/src/jdk.crypto.pkcs11/unix/native/libj2pkcs11/p11_md.h jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.c jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.h jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.c jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.h jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java jdk/src/jdk.pack200/share/classes/module-info.java jdk/src/jdk.pack200/share/native/common-unpack/bands.cpp jdk/src/jdk.pack200/share/native/common-unpack/bands.h jdk/src/jdk.pack200/share/native/common-unpack/bytes.cpp jdk/src/jdk.pack200/share/native/common-unpack/bytes.h jdk/src/jdk.pack200/share/native/common-unpack/coding.cpp jdk/src/jdk.pack200/share/native/common-unpack/coding.h jdk/src/jdk.pack200/share/native/common-unpack/constants.h jdk/src/jdk.pack200/share/native/common-unpack/defines.h jdk/src/jdk.pack200/share/native/common-unpack/unpack.cpp jdk/src/jdk.pack200/share/native/common-unpack/unpack.h jdk/src/jdk.pack200/share/native/common-unpack/utils.cpp jdk/src/jdk.pack200/share/native/common-unpack/utils.h jdk/src/jdk.pack200/share/native/common-unpack/zip.cpp jdk/src/jdk.pack200/share/native/common-unpack/zip.h jdk/src/jdk.pack200/share/native/libunpack/jni.cpp jdk/src/jdk.pack200/share/native/unpack200/main.cpp jdk/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest jdk/test/tools/jlink/plugins/FileCopierPluginTest.java
diffstat 511 files changed, 57340 insertions(+), 57090 deletions(-) [+]
line wrap: on
line diff
--- a/jdk/.hgtags	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/.hgtags	Mon Dec 19 09:16:40 2016 -0800
@@ -391,3 +391,4 @@
 6e4ff59afb5d0adf21a72c4ff534326594a99e5d jdk-9+146
 c41140100bf1e5c10c7b8f3bde91c16eff7485f5 jdk-9+147
 9098b2b9d997d65af0026fc2f39cf75234e26bc5 jdk-9+148
+5a846396a24c7aff01d6a8feaa7afc0a6369f04d jdk-9+149
--- a/jdk/make/copy/Copy-java.base.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/make/copy/Copy-java.base.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -100,8 +100,7 @@
   # Allow override by ALT_JVMCFG_SRC if it exists
   JVMCFG_SRC := $(if $(wildcard $(ALT_JVMCFG_SRC)),$(ALT_JVMCFG_SRC),$(JVMCFG_SRC))
 endif
-JVMCFG_DIR := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR)
-JVMCFG := $(JVMCFG_DIR)/jvm.cfg
+JVMCFG := $(LIB_DST_DIR)/jvm.cfg
 
 # To do: should this also support -zeroshark?
 
--- a/jdk/make/copy/Copy-java.desktop.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/make/copy/Copy-java.desktop.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -64,7 +64,7 @@
   ifeq ($(OPENJDK_TARGET_OS), windows)
     FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype)
   else
-    FREETYPE_TARGET_LIB := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR)/$(call SHARED_LIBRARY,freetype).6
+    FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype).6
   endif
 
   # We can't use $(install-file) in this rule because it preserves symbolic links and
--- a/jdk/make/copy/Copy-jdk.crypto.pkcs11.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-#
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include CopyCommon.gmk
-
-################################################################################
-
-ifeq ($(OPENJDK_TARGET_OS), solaris)
-
-  SUNPKCS11_CFG_SRC := \
-      $(JDK_TOPDIR)/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg
-  SUNPKCS11_CFG_DST := $(CONF_DST_DIR)/security/sunpkcs11-solaris.cfg
-
-  $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC)
-	$(call install-file)
-
-  SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST)
-
-  TARGETS := $(SUNPKCS11_CFG_DST)
-
-endif
-
-################################################################################
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/copy/Copy-jdk.crypto.token.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include CopyCommon.gmk
+
+################################################################################
+
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+  SUNPKCS11_CFG_SRC := \
+      $(JDK_TOPDIR)/src/jdk.crypto.token/solaris/conf/security/sunpkcs11-solaris.cfg
+  SUNPKCS11_CFG_DST := $(CONF_DST_DIR)/security/sunpkcs11-solaris.cfg
+
+  $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC)
+	$(call install-file)
+
+  SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST)
+
+  TARGETS := $(SUNPKCS11_CFG_DST)
+
+endif
+
+################################################################################
--- a/jdk/make/launcher/Launcher-java.base.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/make/launcher/Launcher-java.base.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -74,7 +74,7 @@
 BUILD_JEXEC :=
 BUILD_JEXEC_SRC :=
 BUILD_JEXEC_INC :=
-BUILD_JEXEC_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
+BUILD_JEXEC_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
 
 #
 # UNHANDLED:
@@ -138,7 +138,7 @@
 BUILD_JSPAWNHELPER :=
 BUILD_JSPAWNHELPER_SRC := $(JDK_TOPDIR)/src/java.base/unix/native/jspawnhelper
 JSPAWNHELPER_CFLAGS := -I$(JDK_TOPDIR)/src/java.base/unix/native/libjava
-BUILD_JSPAWNHELPER_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
+BUILD_JSPAWNHELPER_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
 LINK_JSPAWNHELPER_OBJECTS := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjava/childproc.o
 BUILD_JSPAWNHELPER_LDFLAGS :=
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/launcher/Launcher-jdk.aot.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -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.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LauncherCommon.gmk
+
+$(eval $(call SetupBuildLauncher, jaotc, \
+    MAIN_CLASS := jdk.tools.jaotc.Main, \
+    JAVA_ARGS := -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI \
+        -XX:+UseAOT \
+        -Djvmci.UseProfilingInformation=false \
+        -Dgraal.UseExceptionProbability=false \
+        -Djvmci.Compiler=graal \
+        --add-modules ALL-DEFAULT \
+    , \
+))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/launcher/Launcher-jdk.pack.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -0,0 +1,112 @@
+#
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LauncherCommon.gmk
+
+$(eval $(call SetupBuildLauncher, pack200, \
+    MAIN_MODULE := java.base, \
+    MAIN_CLASS := com.sun.java.util.jar.pack.Driver, \
+))
+
+################################################################################
+# The order of the object files on the link command line affects the size of the resulting
+# binary (at least on linux) which causes the size to differ between old and new build.
+
+UNPACKEXE_SRC := $(JDK_TOPDIR)/src/jdk.pack/share/native/common-unpack \
+    $(JDK_TOPDIR)/src/jdk.pack/share/native/unpack200
+UNPACKEXE_CFLAGS := -I$(JDK_TOPDIR)/src/jdk.pack/share/native/common-unpack \
+    -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \
+    -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava
+
+ifeq ($(USE_EXTERNAL_LIBZ), true)
+  UNPACKEXE_CFLAGS += -DSYSTEM_ZLIB
+  UNPACKEXE_LIBS := -lz
+else
+  UNPACKEXE_CFLAGS += -I$(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8
+  UNPACKEXE_ZIPOBJS := $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zcrc32$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/deflate$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/trees$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zadler32$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/compress$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zutil$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inflate$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/infback$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inftrees$(OBJ_SUFFIX) \
+      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inffast$(OBJ_SUFFIX)
+
+endif
+
+UNPACK_MAPFILE_DIR := $(JDK_TOPDIR)/make/mapfiles/libunpack
+UNPACK_MAPFILE_PLATFORM_FILE := \
+    $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH)
+
+# The linker on older SuSE distros (e.g. on SLES 10) complains with:
+# "Invalid version tag `SUNWprivate_1.1'. Only anonymous version tag is allowed in executable."
+# if feeded with a version script which contains named tags.
+ifeq ($(USING_BROKEN_SUSE_LD), yes)
+  UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200.anonymous
+else ifneq ($(wildcard $(UNPACK_MAPFILE_PLATFORM_FILE)), )
+  UNPACK_MAPFILE := $(UNPACK_MAPFILE_PLATFORM_FILE)
+else
+  UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200
+endif
+
+$(eval $(call SetupNativeCompilation,BUILD_UNPACKEXE, \
+    SRC := $(UNPACKEXE_SRC), \
+    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
+    OPTIMIZATION := LOW, \
+    CFLAGS := $(UNPACKEXE_CFLAGS) $(CXXFLAGS_JDKEXE) -DFULL, \
+    CFLAGS_release := -DPRODUCT, \
+    CFLAGS_linux := -fPIC, \
+    CFLAGS_solaris := -KPIC, \
+    CFLAGS_macosx := -fPIC, \
+    DISABLED_WARNINGS_gcc := unused-result, \
+    MAPFILE := $(UNPACK_MAPFILE),\
+    LDFLAGS := $(UNPACKEXE_ZIPOBJS) \
+        $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \
+        $(call SET_SHARED_LIBRARY_ORIGIN), \
+    LIBS := $(UNPACKEXE_LIBS) $(LIBCXX), \
+    LIBS_solaris :=  -lc, \
+    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpackexe, \
+    OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/$(MODULE), \
+    PROGRAM := unpack200, \
+    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+    RC_FLAGS := $(RC_FLAGS) \
+        -D "JDK_FNAME=unpack200.exe" \
+        -D "JDK_INTERNAL_NAME=unpack200" \
+        -D "JDK_FTYPE=0x1L", \
+    MANIFEST := $(JDK_TOPDIR)/src/jdk.pack/windows/native/unpack200/unpack200_proto.exe.manifest, \
+    MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS), \
+))
+
+ifneq ($(USE_EXTERNAL_LIBZ), true)
+
+  $(BUILD_UNPACKEXE): $(UNPACKEXE_ZIPOBJS)
+
+endif
+
+TARGETS += $(BUILD_UNPACKEXE)
+
+################################################################################
--- a/jdk/make/launcher/Launcher-jdk.pack200.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include LauncherCommon.gmk
-
-$(eval $(call SetupBuildLauncher, pack200, \
-    MAIN_MODULE := java.base, \
-    MAIN_CLASS := com.sun.java.util.jar.pack.Driver, \
-))
-
-################################################################################
-# The order of the object files on the link command line affects the size of the resulting
-# binary (at least on linux) which causes the size to differ between old and new build.
-
-UNPACKEXE_SRC := $(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack \
-    $(JDK_TOPDIR)/src/jdk.pack200/share/native/unpack200
-UNPACKEXE_CFLAGS := -I$(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack \
-    -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \
-    -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava
-
-ifeq ($(USE_EXTERNAL_LIBZ), true)
-  UNPACKEXE_CFLAGS += -DSYSTEM_ZLIB
-  UNPACKEXE_LIBS := -lz
-else
-  UNPACKEXE_CFLAGS += -I$(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8
-  UNPACKEXE_ZIPOBJS := $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zcrc32$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/deflate$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/trees$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zadler32$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/compress$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zutil$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inflate$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/infback$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inftrees$(OBJ_SUFFIX) \
-      $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inffast$(OBJ_SUFFIX)
-
-endif
-
-UNPACK_MAPFILE_DIR := $(JDK_TOPDIR)/make/mapfiles/libunpack
-UNPACK_MAPFILE_PLATFORM_FILE := \
-    $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH)
-
-# The linker on older SuSE distros (e.g. on SLES 10) complains with:
-# "Invalid version tag `SUNWprivate_1.1'. Only anonymous version tag is allowed in executable."
-# if feeded with a version script which contains named tags.
-ifeq ($(USING_BROKEN_SUSE_LD), yes)
-  UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200.anonymous
-else ifneq ($(wildcard $(UNPACK_MAPFILE_PLATFORM_FILE)), )
-  UNPACK_MAPFILE := $(UNPACK_MAPFILE_PLATFORM_FILE)
-else
-  UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200
-endif
-
-$(eval $(call SetupNativeCompilation,BUILD_UNPACKEXE, \
-    SRC := $(UNPACKEXE_SRC), \
-    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
-    OPTIMIZATION := LOW, \
-    CFLAGS := $(UNPACKEXE_CFLAGS) $(CXXFLAGS_JDKEXE) -DFULL, \
-    CFLAGS_release := -DPRODUCT, \
-    CFLAGS_linux := -fPIC, \
-    CFLAGS_solaris := -KPIC, \
-    CFLAGS_macosx := -fPIC, \
-    DISABLED_WARNINGS_gcc := unused-result, \
-    MAPFILE := $(UNPACK_MAPFILE),\
-    LDFLAGS := $(UNPACKEXE_ZIPOBJS) \
-        $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \
-        $(call SET_SHARED_LIBRARY_ORIGIN), \
-    LIBS := $(UNPACKEXE_LIBS) $(LIBCXX), \
-    LIBS_solaris :=  -lc, \
-    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpackexe, \
-    OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/$(MODULE), \
-    PROGRAM := unpack200, \
-    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
-    RC_FLAGS := $(RC_FLAGS) \
-        -D "JDK_FNAME=unpack200.exe" \
-        -D "JDK_INTERNAL_NAME=unpack200" \
-        -D "JDK_FTYPE=0x1L", \
-    MANIFEST := $(JDK_TOPDIR)/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest, \
-    MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS), \
-))
-
-ifneq ($(USE_EXTERNAL_LIBZ), true)
-
-  $(BUILD_UNPACKEXE): $(UNPACKEXE_ZIPOBJS)
-
-endif
-
-TARGETS += $(BUILD_UNPACKEXE)
-
-################################################################################
--- a/jdk/make/launcher/LauncherCommon.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/make/launcher/LauncherCommon.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -32,13 +32,13 @@
   ifeq ($(OPENJDK_TARGET_OS), windows)
     DISABLE_MAPFILES := true
   endif
-  ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN,/../lib$(OPENJDK_TARGET_CPU_LIBDIR)/jli)
+  ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN,/../lib/jli)
 
   # Applications expect to be able to link against libjawt without invoking
   # System.loadLibrary("jawt") first. This was the behaviour described in the
   # devloper documentation of JAWT and what worked with OpenJDK6.
   ifneq ($(findstring $(OPENJDK_TARGET_OS), linux solaris), )
-    ORIGIN_ARG += $(call SET_EXECUTABLE_ORIGIN,/../lib$(OPENJDK_TARGET_CPU_LIBDIR))
+    ORIGIN_ARG += $(call SET_EXECUTABLE_ORIGIN,/../lib)
   endif
 endif
 
@@ -190,9 +190,9 @@
           $$(ORIGIN_ARG) \
           $$($1_LDFLAGS), \
       LDFLAGS_linux := \
-          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
+          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli, \
       LDFLAGS_solaris := $$($1_LDFLAGS_solaris) \
-          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
+          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli, \
       MAPFILE := $$($1_MAPFILE), \
       LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \
       LIBS_unix := $$($1_LIBS_unix), \
--- a/jdk/make/lib/CoreLibraries.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/make/lib/CoreLibraries.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -340,9 +340,6 @@
 
 LIBJLI_CFLAGS += $(addprefix -I, $(LIBJLI_SRC_DIRS))
 
-# Append defines depending on target platform
-LIBJLI_CFLAGS += $(OPENJDK_TARGET_CPU_JLI_CFLAGS)
-
 ifneq ($(USE_EXTERNAL_LIBZ), true)
   LIBJLI_CFLAGS += $(ZLIB_CPPFLAGS)
   LIBJLI_EXTRA_FILES += \
--- a/jdk/make/lib/Lib-jdk.crypto.pkcs11.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include LibCommon.gmk
-
-################################################################################
-
-LIBJ2PKCS11_SRC := $(JDK_TOPDIR)/src/jdk.crypto.pkcs11/share/native/libj2pkcs11 \
-    $(JDK_TOPDIR)/src/jdk.crypto.pkcs11/$(OPENJDK_TARGET_OS_TYPE)/native/libj2pkcs11
-
-$(eval $(call SetupNativeCompilation,BUILD_LIBJ2PKCS11, \
-    LIBRARY := j2pkcs11, \
-    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
-    SRC := $(LIBJ2PKCS11_SRC), \
-    OPTIMIZATION := LOW, \
-    CFLAGS := $(CFLAGS_JDKLIB) $(addprefix -I, $(LIBJ2PKCS11_SRC)) \
-        $(LIBJAVA_HEADER_FLAGS) \
-        -I$(SUPPORT_OUTPUTDIR)/headers/jdk.crypto.pkcs11, \
-    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libj2pkcs11/mapfile-vers, \
-    LDFLAGS := $(LDFLAGS_JDKLIB) \
-        $(call SET_SHARED_LIBRARY_ORIGIN), \
-    LIBS_unix := $(LIBDL), \
-    LIBS_solaris := -lc, \
-    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
-    RC_FLAGS := $(RC_FLAGS) \
-        -D "JDK_FNAME=j2pkcs11.dll" \
-        -D "JDK_INTERNAL_NAME=j2pkcs11" \
-        -D "JDK_FTYPE=0x2L", \
-    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libj2pkcs11, \
-))
-
-TARGETS += $(BUILD_LIBJ2PKCS11)
-
-################################################################################
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/lib/Lib-jdk.crypto.token.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LibCommon.gmk
+
+################################################################################
+
+LIBJ2PKCS11_SRC := $(JDK_TOPDIR)/src/jdk.crypto.token/share/native/libj2pkcs11 \
+    $(JDK_TOPDIR)/src/jdk.crypto.token/$(OPENJDK_TARGET_OS_TYPE)/native/libj2pkcs11
+
+$(eval $(call SetupNativeCompilation,BUILD_LIBJ2PKCS11, \
+    LIBRARY := j2pkcs11, \
+    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+    SRC := $(LIBJ2PKCS11_SRC), \
+    OPTIMIZATION := LOW, \
+    CFLAGS := $(CFLAGS_JDKLIB) $(addprefix -I, $(LIBJ2PKCS11_SRC)) \
+        $(LIBJAVA_HEADER_FLAGS) \
+        -I$(SUPPORT_OUTPUTDIR)/headers/jdk.crypto.token, \
+    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libj2pkcs11/mapfile-vers, \
+    LDFLAGS := $(LDFLAGS_JDKLIB) \
+        $(call SET_SHARED_LIBRARY_ORIGIN), \
+    LIBS_unix := $(LIBDL), \
+    LIBS_solaris := -lc, \
+    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+    RC_FLAGS := $(RC_FLAGS) \
+        -D "JDK_FNAME=j2pkcs11.dll" \
+        -D "JDK_INTERNAL_NAME=j2pkcs11" \
+        -D "JDK_FTYPE=0x2L", \
+    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libj2pkcs11, \
+))
+
+TARGETS += $(BUILD_LIBJ2PKCS11)
+
+################################################################################
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/lib/Lib-jdk.pack.gmk	Mon Dec 19 09:16:40 2016 -0800
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LibCommon.gmk
+
+################################################################################
+
+$(eval $(call SetupNativeCompilation,BUILD_LIBUNPACK, \
+    LIBRARY := unpack, \
+    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+    SRC := $(JDK_TOPDIR)/src/jdk.pack/share/native/libunpack \
+        $(JDK_TOPDIR)/src/jdk.pack/share/native/common-unpack, \
+    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
+    OPTIMIZATION := LOW, \
+    CFLAGS := $(CXXFLAGS_JDKLIB) \
+        -DNO_ZLIB -DUNPACK_JNI -DFULL \
+        -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
+        -I$(JDK_TOPDIR)/src/jdk.pack/share/native/common-unpack \
+        $(LIBJAVA_HEADER_FLAGS), \
+    CFLAGS_release := -DPRODUCT, \
+    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libunpack/mapfile-vers, \
+    LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
+        $(call SET_SHARED_LIBRARY_ORIGIN), \
+    LDFLAGS_windows := -map:$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpack.map -debug, \
+    LIBS_unix := -ljvm $(LIBCXX) -ljava -lc, \
+    LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \
+    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libunpack, \
+    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+    RC_FLAGS := $(RC_FLAGS) \
+        -D "JDK_FNAME=unpack.dll" \
+        -D "JDK_INTERNAL_NAME=unpack" \
+        -D "JDK_FTYPE=0x2L", \
+))
+
+$(BUILD_LIBUNPACK): $(call FindLib, java.base, java)
+
+TARGETS += $(BUILD_LIBUNPACK)
+
+################################################################################
--- a/jdk/make/lib/Lib-jdk.pack200.gmk	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-#
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include LibCommon.gmk
-
-################################################################################
-
-$(eval $(call SetupNativeCompilation,BUILD_LIBUNPACK, \
-    LIBRARY := unpack, \
-    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
-    SRC := $(JDK_TOPDIR)/src/jdk.pack200/share/native/libunpack \
-        $(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack, \
-    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
-    OPTIMIZATION := LOW, \
-    CFLAGS := $(CXXFLAGS_JDKLIB) \
-        -DNO_ZLIB -DUNPACK_JNI -DFULL \
-        -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
-        -I$(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack \
-        $(LIBJAVA_HEADER_FLAGS), \
-    CFLAGS_release := -DPRODUCT, \
-    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libunpack/mapfile-vers, \
-    LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
-        $(call SET_SHARED_LIBRARY_ORIGIN), \
-    LDFLAGS_windows := -map:$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpack.map -debug, \
-    LIBS_unix := -ljvm $(LIBCXX) -ljava -lc, \
-    LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \
-    OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libunpack, \
-    VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
-    RC_FLAGS := $(RC_FLAGS) \
-        -D "JDK_FNAME=unpack.dll" \
-        -D "JDK_INTERNAL_NAME=unpack" \
-        -D "JDK_FTYPE=0x2L", \
-))
-
-$(BUILD_LIBUNPACK): $(call FindLib, java.base, java)
-
-TARGETS += $(BUILD_LIBUNPACK)
-
-################################################################################
--- a/jdk/make/mapfiles/libjava/mapfile-vers	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/make/mapfiles/libjava/mapfile-vers	Mon Dec 19 09:16:40 2016 -0800
@@ -150,7 +150,6 @@
 		Java_java_lang_StrictMath_atan;
 		Java_java_lang_StrictMath_atan2;
 		Java_java_lang_StrictMath_cos;
-		Java_java_lang_StrictMath_exp;
 		Java_java_lang_StrictMath_log;
 		Java_java_lang_StrictMath_log10;
 		Java_java_lang_StrictMath_sin;
--- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Mon Dec 19 09:16:40 2016 -0800
@@ -26,6 +26,7 @@
 package build.tools.jigsaw;
 
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
@@ -35,14 +36,17 @@
 import java.nio.file.Files;
 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.Set;
 import java.util.TreeSet;
 import java.util.function.Function;
-import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.*;
 import static java.lang.module.ModuleDescriptor.Requires.Modifier.TRANSITIVE;
 
 /**
@@ -67,42 +71,25 @@
                                   .map(ModuleReference::descriptor)
                                   .filter(m -> (m.name().startsWith("java.") &&
                                                !m.name().equals("java.smartcardio")))
-                                  .collect(Collectors.toSet()));
+                                  .collect(toSet()));
         Set<ModuleDescriptor> jdkModules
             = new TreeSet<>(finder.findAll().stream()
                                   .map(ModuleReference::descriptor)
                                   .filter(m -> !javaSEModules.contains(m))
-                                  .collect(Collectors.toSet()));
+                                  .collect(toSet()));
 
-        GenGraphs genGraphs = new GenGraphs(javaSEModules, jdkModules);
+        GenGraphs genGraphs = new GenGraphs(dir, javaSEModules, jdkModules);
         Set<String> mods = new HashSet<>();
         for (ModuleReference mref: finder.findAll()) {
-            ModuleDescriptor descriptor = mref.descriptor();
-            String name = descriptor.name();
-            mods.add(name);
-            Configuration cf = Configuration.empty()
-                    .resolveRequires(finder,
-                                     ModuleFinder.of(),
-                                     Set.of(name));
-            genGraphs.genDotFile(dir, name, cf);
+            mods.add(mref.descriptor().name());
+            genGraphs.genDotFile(mref);
         }
 
-        Configuration cf = Configuration.empty()
-                .resolveRequires(finder,
-                                 ModuleFinder.of(),
-                                 mods);
-        genGraphs.genDotFile(dir, "jdk", cf);
+        // all modules
+        genGraphs.genDotFile("jdk", mods);
 
     }
 
-    private final Set<ModuleDescriptor> javaGroup;
-    private final Set<ModuleDescriptor> jdkGroup;
-
-    GenGraphs(Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
-        this.javaGroup = Collections.unmodifiableSet(javaGroup);
-        this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
-    }
-
     private static final String ORANGE = "#e76f00";
     private static final String BLUE = "#437291";
     private static final String GRAY = "#dddddd";
@@ -112,6 +99,7 @@
     private static final String REQUIRES_BASE = "color=\"" + GRAY + "\"";
 
     private static final Map<String,Integer> weights = new HashMap<>();
+    private static final List<Set<String>> ranks = new ArrayList<>();
 
     private static void weight(String s, String t, int w) {
         weights.put(s + ":" + t, w);
@@ -128,23 +116,84 @@
 
     static {
         int h = 1000;
-        weight("java.se", "java.compact3", h * 10);
-        weight("jdk.compact3", "java.compact3", h * 10);
-        weight("java.compact3", "java.compact2", h * 10);
-        weight("java.compact2", "java.compact1", h * 10);
-        weight("java.compact1", "java.logging", h * 10);
-        weight("java.logging", "java.base", h * 10);
+        weight("java.se", "java.sql.rowset", h * 10);
+        weight("java.sql.rowset", "java.sql", h * 10);
+        weight("java.sql", "java.xml", h * 10);
+        weight("java.xml", "java.base", h * 10);
+
+        ranks.add(Set.of("java.logging", "java.scripting", "java.xml"));
+        ranks.add(Set.of("java.sql"));
+        ranks.add(Set.of("java.compiler", "java.instrument"));
+        ranks.add(Set.of("java.desktop", "java.management"));
+        ranks.add(Set.of("java.corba", "java.xml.ws"));
+        ranks.add(Set.of("java.xml.bind", "java.annotations.common"));
+
     }
 
-    private void genDotFile(Path dir, String name, Configuration cf) throws IOException {
-        try (PrintStream out
-                 = new PrintStream(Files.newOutputStream(dir.resolve(name + ".dot")))) {
+    private final Path dir;
+    private final Set<ModuleDescriptor> javaGroup;
+    private final Set<ModuleDescriptor> jdkGroup;
 
-            Map<String, ModuleDescriptor> nameToModule = cf.modules().stream()
-                    .map(ResolvedModule::reference)
-                    .map(ModuleReference::descriptor)
-                    .collect(Collectors.toMap(ModuleDescriptor::name, Function.identity()));
+    GenGraphs(Path dir, Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
+        this.dir = dir;
+        this.javaGroup = Collections.unmodifiableSet(javaGroup);
+        this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
+    }
 
+    /**
+     * Generates a dot file for the given module reference as the root.
+     */
+    void genDotFile(ModuleReference mref) throws IOException {
+        String name = mref.descriptor().name();
+        genDotFile(name, Set.of(name));
+    }
+
+    /**
+     * Generates a dot file for the given set of root modules.
+     */
+    void genDotFile(String name, Set<String> roots) throws IOException {
+        Configuration cf =
+            Configuration.empty().resolveRequires(ModuleFinder.ofSystem(),
+                                                  ModuleFinder.of(),
+                                                  roots);
+
+        Set<ModuleDescriptor> mds = cf.modules().stream()
+                .map(ResolvedModule::reference)
+                .map(ModuleReference::descriptor)
+                .collect(toSet());
+
+        // generate a dot file for the resolved graph
+        try (OutputStream os = Files.newOutputStream(dir.resolve(name + ".dot"));
+             PrintStream out = new PrintStream(os)) {
+            printGraph(out, name, gengraph(cf),
+                       mds.stream()
+                          .collect(toMap(ModuleDescriptor::name, Function.identity()))
+            );
+        }
+
+        if (name.equals("java.se") || name.equals("java.se.ee")) {
+            // generate a dot file for Java SE module graph
+            try (OutputStream os = Files.newOutputStream(dir.resolve(name + "-spec.dot"));
+                 PrintStream out = new PrintStream(os)) {
+                // transitive reduction on the graph of `requires transitive` edges
+                // filter out jdk.* modules which are implementation dependences
+                Graph<String> graph = requiresTransitiveGraph(cf, true);
+                printGraph(out, name, graph,
+                           mds.stream()
+                              .filter(md -> !md.name().startsWith("jdk.") &&
+                                                graph.nodes().contains(md.name()))
+                              .collect(toMap(ModuleDescriptor::name, Function.identity()))
+                );
+            }
+        }
+    }
+
+    private void printGraph(PrintStream out,
+                            String name,
+                            Graph<String> graph,
+                            Map<String, ModuleDescriptor> nameToModule)
+        throws IOException
+    {
             Set<ModuleDescriptor> descriptors = new TreeSet<>(nameToModule.values());
 
             out.format("digraph \"%s\" {%n", name);
@@ -162,33 +211,45 @@
                 .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
                                           mn, ORANGE, "java"));
             out.format("}%n");
+
+            // same ranks
+            ranks.stream()
+                .map(group -> descriptors.stream()
+                                         .map(ModuleDescriptor::name)
+                                         .filter(group::contains)
+                                         .map(mn -> "\"" + mn + "\"")
+                                         .collect(joining(",")))
+                .filter(group -> group.length() > 0)
+                .forEach(group -> out.format("{rank=same %s}%n", group));
+
             descriptors.stream()
                 .filter(jdkGroup::contains)
                 .map(ModuleDescriptor::name)
                 .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
                                           mn, BLUE, "jdk"));
 
-            // transitive reduction
-            Graph<String> graph = gengraph(cf);
-            descriptors.forEach(md -> {
-                String mn = md.name();
-                Set<String> requiresTransitive = md.requires().stream()
-                        .filter(d -> d.modifiers().contains(TRANSITIVE))
-                        .map(d -> d.name())
-                        .collect(Collectors.toSet());
+            descriptors.stream()
+                .forEach(md -> {
+                    String mn = md.name();
+                    Set<String> requiresTransitive = md.requires().stream()
+                            .filter(d -> d.modifiers().contains(TRANSITIVE))
+                            .map(d -> d.name())
+                            .collect(toSet());
 
-                graph.adjacentNodes(mn).forEach(dn -> {
-                    String attr = dn.equals("java.base") ? REQUIRES_BASE
-                            : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
-                    int w = weightOf(mn, dn);
-                    if (w > 1)
-                        attr += "weight=" + w;
-                    out.format("  \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
+                    graph.adjacentNodes(mn)
+                         .stream()
+                         .filter(nameToModule::containsKey)
+                         .forEach(dn -> {
+                             String attr = dn.equals("java.base") ? REQUIRES_BASE
+                                    : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
+                             int w = weightOf(mn, dn);
+                             if (w > 1)
+                                 attr += "weight=" + w;
+                             out.format("  \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
+                         });
                 });
-            });
 
             out.println("}");
-        }
     }
 
     /**
@@ -208,7 +269,7 @@
                     .map(ResolvedModule::name)
                     .forEach(target -> builder.addEdge(mn, target));
         }
-        Graph<String> rpg = requiresTransitiveGraph(cf);
+        Graph<String> rpg = requiresTransitiveGraph(cf, false);
         return builder.build().reduce(rpg);
     }
 
@@ -216,13 +277,14 @@
      * Returns a Graph containing only requires transitive edges
      * with transitive reduction.
      */
-    private Graph<String> requiresTransitiveGraph(Configuration cf) {
+    private Graph<String> requiresTransitiveGraph(Configuration cf, boolean includeBase) {
         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(TRANSITIVE))
+                    .filter(d -> d.modifiers().contains(TRANSITIVE)
+                                    || (includeBase && d.name().equals("java.base")))
                     .map(d -> d.name())
                     .forEach(d -> builder.addEdge(mn, d));
         }
--- a/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c	Mon Dec 19 09:16:40 2016 -0800
@@ -171,8 +171,6 @@
  * Main
  */
 
-#define GetArch() GetArchPath(CURRENT_DATA_MODEL)
-
 /* Store the name of the executable once computed */
 static char *execname = NULL;
 
@@ -184,16 +182,6 @@
     return execname;
 }
 
-const char *
-GetArchPath(int nbits)
-{
-    switch(nbits) {
-        default:
-            return LIBARCHNAME;
-    }
-}
-
-
 /*
  * Exports the JNI interface from libjli
  *
@@ -211,7 +199,7 @@
     if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions;
 
     char jrePath[PATH_MAX];
-    jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE);
+    jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE);
     if (!gotJREPath) {
         JLI_ReportErrorMessage("Failed to GetJREPath()");
         return NULL;
@@ -229,7 +217,7 @@
     }
 
     char jvmPath[PATH_MAX];
-    jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
+    jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), CURRENT_DATA_MODEL);
     if (!gotJVMPath) {
         JLI_ReportErrorMessage("Failed to GetJVMPath()");
         return NULL;
@@ -390,7 +378,6 @@
 
     /* Check data model flags, and exec process, if needed */
     {
-      char *arch        = (char *)GetArch(); /* like sparc or sparcv9 */
       char * jvmtype    = NULL;
       int  argc         = *pargc;
       char **argv       = *pargv;
@@ -462,7 +449,7 @@
          jvmpath does not exist */
       if (wanted == running) {
         /* Find out where the JRE is that we will be using. */
-        if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
+        if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
           JLI_ReportErrorMessage(JRE_ERROR1);
           exit(2);
         }
@@ -481,7 +468,7 @@
             exit(4);
         }
 
-        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, wanted)) {
+        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, wanted)) {
           JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
           exit(4);
         }
@@ -502,7 +489,7 @@
 #if defined(DUAL_MODE)
         if (running != wanted) {
           /* Find out where the JRE is that we will be using. */
-          if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) {
+          if (!GetJREPath(jrepath, so_jrepath, JNI_TRUE)) {
             /* give up and let other code report error message */
             JLI_ReportErrorMessage(JRE_ERROR2, wanted);
             exit(1);
@@ -526,7 +513,7 @@
           }
 
           /* exec child can do error checking on the existence of the path */
-          jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted), wanted);
+          jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, wanted);
         }
 #else /* ! DUAL_MODE */
         JLI_ReportErrorMessage(JRE_ERROR2, wanted);
@@ -579,7 +566,7 @@
  */
 static jboolean
 GetJVMPath(const char *jrepath, const char *jvmtype,
-           char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
+           char *jvmpath, jint jvmpathsize, int bitsWanted)
 {
     struct stat s;
 
@@ -613,7 +600,7 @@
  * Find path to JRE based on .exe's location or registry settings.
  */
 static jboolean
-GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
+GetJREPath(char *path, jint pathsize, jboolean speculative)
 {
     char libjava[MAXPATHLEN];
 
@@ -841,7 +828,7 @@
 void* SplashProcAddress(const char* name) {
     if (!hSplashLib) {
         char jrePath[PATH_MAX];
-        if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) {
+        if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
             JLI_ReportErrorMessage(JRE_ERROR1);
             return NULL;
         }
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java	Mon Dec 19 09:16:40 2016 -0800
@@ -142,6 +142,9 @@
      */
     int encrypt(byte[] plain, int plainOffset, int plainLen,
                 byte[] cipher, int cipherOffset) {
+        if (plainLen <= 0) {
+            return plainLen;
+        }
         cryptBlockSizeCheck(plainLen);
         cryptNullAndBoundsCheck(plain, plainOffset, plainLen);
         cryptNullAndBoundsCheck(cipher, cipherOffset, plainLen);
@@ -190,6 +193,9 @@
      */
     int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
                 byte[] plain, int plainOffset) {
+        if (cipherLen <= 0) {
+            return cipherLen;
+        }
         cryptBlockSizeCheck(cipherLen);
         cryptNullAndBoundsCheck(cipher, cipherOffset, cipherLen);
         cryptNullAndBoundsCheck(plain, plainOffset, cipherLen);
@@ -220,10 +226,6 @@
     }
 
     private static void cryptNullAndBoundsCheck(byte[] array, int offset, int len) {
-        if (len <= 0) {
-            return; // not an error because cryptImpl/decryptImpl won't execute if len <= 0
-        }
-
         Objects.requireNonNull(array);
 
         if (offset < 0 || offset >= array.length) {
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java	Mon Dec 19 09:16:40 2016 -0800
@@ -172,10 +172,12 @@
      * are encrypted on demand.
      */
     private int crypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
-
-      Objects.checkFromIndexSize(inOff, len, in.length);
-      Objects.checkFromIndexSize(outOff, len, out.length);
-      return implCrypt(in, inOff, len, out, outOff);
+        if (len == 0) {
+            return 0;
+        }
+        Objects.checkFromIndexSize(inOff, len, in.length);
+        Objects.checkFromIndexSize(outOff, len, out.length);
+        return implCrypt(in, inOff, len, out, outOff);
     }
 
     // Implementation of crpyt() method. Possibly replaced with a compiler intrinsic.
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java	Mon Dec 19 09:16:40 2016 -0800
@@ -317,7 +317,7 @@
                 this(null, je);
             }
             boolean isClassFile() {
-                if (!name.endsWith(".class")) {
+                if (!name.endsWith(".class") || name.endsWith("module-info.class")) {
                     return false;
                 }
                 for (String prefix = name;;) {
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Mon Dec 19 09:16:40 2016 -0800
@@ -14,15 +14,6 @@
 pack.class.attribute.SourceID = RUH
 pack.class.attribute.CompilationID = RUH
 
-# Module attributes, supported by the tool and not JSR-200
-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.
 # They are automatically defined to have an empty layout.
 #pack.class.attribute.Deprecated =
--- a/jdk/src/java.base/share/classes/java/io/FilePermission.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/io/FilePermission.java	Mon Dec 19 09:16:40 2016 -0800
@@ -206,12 +206,6 @@
             DefaultFileSystemProvider.create()
                     .getFileSystem(URI.create("file:///"));
 
-    /**
-     * Creates FilePermission objects with special internals.
-     * See {@link FilePermCompat#newPermPlusAltPath(Permission)} and
-     * {@link FilePermCompat#newPermUsingAltPath(Permission)}.
-     */
-
     private static final Path here = builtInFS.getPath(
             GetPropertyAction.privilegedGetProperty("user.dir"));
 
@@ -261,9 +255,14 @@
 
     static {
         SharedSecrets.setJavaIOFilePermissionAccess(
+            /**
+             * Creates FilePermission objects with special internals.
+             * See {@link FilePermCompat#newPermPlusAltPath(Permission)} and
+             * {@link FilePermCompat#newPermUsingAltPath(Permission)}.
+             */
             new JavaIOFilePermissionAccess() {
                 public FilePermission newPermPlusAltPath(FilePermission input) {
-                    if (input.npath2 == null && !input.allFiles) {
+                    if (!input.invalid && input.npath2 == null && !input.allFiles) {
                         Path npath2 = altPath(input.npath);
                         if (npath2 != null) {
                             // Please note the name of the new permission is
@@ -281,7 +280,7 @@
                     return input;
                 }
                 public FilePermission newPermUsingAltPath(FilePermission input) {
-                    if (!input.allFiles) {
+                    if (!input.invalid && !input.allFiles) {
                         Path npath2 = altPath(input.npath);
                         if (npath2 != null) {
                             // New name, see above.
@@ -340,6 +339,16 @@
                 // Windows. Some JDK codes generate such illegal names.
                 npath = builtInFS.getPath(new File(name).getPath())
                         .normalize();
+                // lastName should always be non-null now
+                Path lastName = npath.getFileName();
+                if (lastName != null && lastName.toString().equals("-")) {
+                    directory = true;
+                    recursive = !rememberStar;
+                    npath = npath.getParent();
+                }
+                if (npath == null) {
+                    npath = builtInFS.getPath("");
+                }
                 invalid = false;
             } catch (InvalidPathException ipe) {
                 // Still invalid. For compatibility reason, accept it
@@ -348,16 +357,6 @@
                 invalid = true;
             }
 
-            // lastName should always be non-null now
-            Path lastName = npath.getFileName();
-            if (lastName != null && lastName.toString().equals("-")) {
-                directory = true;
-                recursive = !rememberStar;
-                npath = npath.getParent();
-            }
-            if (npath == null) {
-                npath = builtInFS.getPath("");
-            }
         } else {
             if ((cpath = getName()) == null)
                 throw new NullPointerException("name can't be null");
@@ -452,6 +451,8 @@
      * is converted to a {@link java.nio.file.Path} object named {@code npath}
      * after {@link Path#normalize() normalization}. No canonicalization is
      * performed which means the underlying file system is not accessed.
+     * If an {@link InvalidPathException} is thrown during the conversion,
+     * this {@code FilePermission} will be labeled as invalid.
      * <P>
      * In either case, the "*" or "-" character at the end of a wildcard
      * {@code path} is removed before canonicalization or normalization.
@@ -532,7 +533,12 @@
      * {@code  simple_npath.relativize(wildcard_npath)} is exactly "..",
      * a simple {@code npath} is recursively inside a wildcard {@code npath}
      * if and only if {@code simple_npath.relativize(wildcard_npath)}
-     * is a series of one or more "..".
+     * is a series of one or more "..". An invalid {@code FilePermission} does
+     * not imply any object except for itself. An invalid {@code FilePermission}
+     * is not implied by any object except for itself or a {@code FilePermission}
+     * on {@literal "<<ALL FILES>>"} whose actions is a superset of this
+     * invalid {@code FilePermission}. Even if two {@code FilePermission}
+     * are created with the same invalid path, one does not imply the other.
      *
      * @param p the permission to check against.
      *
@@ -566,12 +572,12 @@
             if (this == that) {
                 return true;
             }
+            if (allFiles) {
+                return true;
+            }
             if (this.invalid || that.invalid) {
                 return false;
             }
-            if (allFiles) {
-                return true;
-            }
             if (that.allFiles) {
                 return false;
             }
@@ -699,6 +705,10 @@
      * (if {@code jdk.io.permissionsUseCanonicalPath} is {@code true}) or
      * {@code npath} (if {@code jdk.io.permissionsUseCanonicalPath}
      * is {@code false}) are equal. Or they are both {@literal "<<ALL FILES>>"}.
+     * <p>
+     * When {@code jdk.io.permissionsUseCanonicalPath} is {@code false}, an
+     * invalid {@code FilePermission} does not equal to any object except
+     * for itself, even if they are created using the same invalid path.
      *
      * @param obj the object we are testing for equality with this object.
      * @return <code>true</code> if obj is a FilePermission, and has the same
--- a/jdk/src/java.base/share/classes/java/lang/FdLibm.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/FdLibm.java	Mon Dec 19 09:16:40 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, 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
@@ -79,7 +79,8 @@
      */
     private static double __LO(double x, int low) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L)|low );
+        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L) |
+                                       (low    & 0x0000_0000_FFFF_FFFFL));
     }
 
     /**
@@ -96,7 +97,8 @@
      */
     private static double __HI(double x, int high) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL)|( ((long)high)) << 32 );
+        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL) |
+                                       ( ((long)high)) << 32 );
     }
 
     /**
@@ -580,4 +582,152 @@
             return s * z;
         }
     }
+
+    /**
+     * Returns the exponential of x.
+     *
+     * Method
+     *   1. Argument reduction:
+     *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+     *      Given x, find r and integer k such that
+     *
+     *               x = k*ln2 + r,  |r| <= 0.5*ln2.
+     *
+     *      Here r will be represented as r = hi-lo for better
+     *      accuracy.
+     *
+     *   2. Approximation of exp(r) by a special rational function on
+     *      the interval [0,0.34658]:
+     *      Write
+     *          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+     *      We use a special Reme algorithm on [0,0.34658] to generate
+     *      a polynomial of degree 5 to approximate R. The maximum error
+     *      of this polynomial approximation is bounded by 2**-59. In
+     *      other words,
+     *          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+     *      (where z=r*r, and the values of P1 to P5 are listed below)
+     *      and
+     *          |                  5          |     -59
+     *          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2
+     *          |                             |
+     *      The computation of exp(r) thus becomes
+     *                             2*r
+     *              exp(r) = 1 + -------
+     *                            R - r
+     *                                 r*R1(r)
+     *                     = 1 + r + ----------- (for better accuracy)
+     *                                2 - R1(r)
+     *      where
+     *                               2       4             10
+     *              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+     *
+     *   3. Scale back to obtain exp(x):
+     *      From step 1, we have
+     *         exp(x) = 2^k * exp(r)
+     *
+     * Special cases:
+     *      exp(INF) is INF, exp(NaN) is NaN;
+     *      exp(-INF) is 0, and
+     *      for finite argument, only exp(0)=1 is exact.
+     *
+     * Accuracy:
+     *      according to an error analysis, the error is always less than
+     *      1 ulp (unit in the last place).
+     *
+     * Misc. info.
+     *      For IEEE double
+     *          if x >  7.09782712893383973096e+02 then exp(x) overflow
+     *          if x < -7.45133219101941108420e+02 then exp(x) underflow
+     *
+     * Constants:
+     * The hexadecimal values are the intended ones for the following
+     * constants. The decimal values may be used, provided that the
+     * compiler will convert from decimal to binary accurately enough
+     * to produce the hexadecimal values shown.
+     */
+    static class Exp {
+        private static final double one     = 1.0;
+        private static final double[] half = {0.5, -0.5,};
+        private static final double huge    = 1.0e+300;
+        private static final double twom1000=     0x1.0p-1000;             //  9.33263618503218878990e-302 = 2^-1000
+        private static final double o_threshold=  0x1.62e42fefa39efp9;     //  7.09782712893383973096e+02
+        private static final double u_threshold= -0x1.74910d52d3051p9;     // -7.45133219101941108420e+02;
+        private static final double[] ln2HI   ={  0x1.62e42feep-1,         //  6.93147180369123816490e-01
+                                                 -0x1.62e42feep-1};        // -6.93147180369123816490e-01
+        private static final double[] ln2LO   ={  0x1.a39ef35793c76p-33,   //  1.90821492927058770002e-10
+                                                 -0x1.a39ef35793c76p-33};  // -1.90821492927058770002e-10
+        private static final double invln2 =      0x1.71547652b82fep0;     //  1.44269504088896338700e+00
+
+        private static final double P1   =  0x1.555555555553ep-3;  //  1.66666666666666019037e-01
+        private static final double P2   = -0x1.6c16c16bebd93p-9;  // -2.77777777770155933842e-03
+        private static final double P3   =  0x1.1566aaf25de2cp-14; //  6.61375632143793436117e-05
+        private static final double P4   = -0x1.bbd41c5d26bf1p-20; // -1.65339022054652515390e-06
+        private static final double P5   =  0x1.6376972bea4d0p-25; //  4.13813679705723846039e-08
+
+        // should be able to forgo strictfp due to controlled over/underflow
+        public static strictfp double compute(double x) {
+            double y;
+            double hi = 0.0;
+            double lo = 0.0;
+            double c;
+            double t;
+            int k = 0;
+            int xsb;
+            /*unsigned*/ int hx;
+
+            hx  = __HI(x);  /* high word of x */
+            xsb = (hx >> 31) & 1;               /* sign bit of x */
+            hx &= 0x7fffffff;               /* high word of |x| */
+
+            /* filter out non-finite argument */
+            if (hx >= 0x40862E42) {                  /* if |x| >= 709.78... */
+                if (hx >= 0x7ff00000) {
+                    if (((hx & 0xfffff) | __LO(x)) != 0)
+                        return x + x;                /* NaN */
+                    else
+                        return (xsb == 0) ? x : 0.0;    /* exp(+-inf) = {inf, 0} */
+                }
+                if (x > o_threshold)
+                    return huge * huge; /* overflow */
+                if (x < u_threshold) // unsigned compare needed here?
+                    return twom1000 * twom1000; /* underflow */
+            }
+
+            /* argument reduction */
+            if (hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */
+                if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                    hi = x - ln2HI[xsb];
+                    lo=ln2LO[xsb];
+                    k = 1 - xsb - xsb;
+                } else {
+                    k  = (int)(invln2 * x + half[xsb]);
+                    t  = k;
+                    hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                    lo = t*ln2LO[0];
+                }
+                x  = hi - lo;
+            } else if (hx < 0x3e300000)  {     /* when |x|<2**-28 */
+                if (huge + x > one)
+                    return one + x; /* trigger inexact */
+            } else {
+                k = 0;
+            }
+
+            /* x is now in primary range */
+            t  = x * x;
+            c  = x - t*(P1 + t*(P2 + t*(P3 + t*(P4 + t*P5))));
+            if (k == 0)
+                return one - ((x*c)/(c - 2.0) - x);
+            else
+                y = one - ((lo - (x*c)/(2.0 - c)) - hi);
+
+            if(k >= -1021) {
+                y = __HI(y, __HI(y) + (k << 20)); /* add k to y's exponent */
+                return y;
+            } else {
+                y = __HI(y, __HI(y) + ((k + 1000) << 20)); /* add k to y's exponent */
+                return y * twom1000;
+            }
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java	Mon Dec 19 09:16:40 2016 -0800
@@ -26,11 +26,13 @@
 package java.lang;
 
 import jdk.internal.loader.BuiltinClassLoader;
-import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
 
 import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.util.HashSet;
@@ -51,12 +53,13 @@
  * @author Josh Bloch
  */
 public final class StackTraceElement implements java.io.Serializable {
-    // This field is set to the compacted String representation used
-    // by StackTraceElement::toString and stored in serial form.
+
+    // For Throwables and StackWalker, the VM initially sets this field to a
+    // reference to the declaring Class.  The Class reference is used to
+    // construct the 'format' bitmap, and then is cleared.
     //
-    // This field is of Object type. VM initially sets this field to
-    // the Class object of the declaring class to build the compacted string.
-    private Object classOrLoaderModuleClassName;
+    // For STEs constructed using the public constructors, this field is not used.
+    private transient Class<?> declaringClassObject;
 
     // Normally initialized by VM
     private String classLoaderName;
@@ -66,6 +69,7 @@
     private String methodName;
     private String fileName;
     private int    lineNumber;
+    private byte   format = 0; // Default to show all
 
     /**
      * Creates a stack trace element representing the specified execution
@@ -256,9 +260,10 @@
     }
 
     /**
-     * Returns a string representation of this stack trace element.  The
-     * format of this string depends on the implementation, but the following
-     * examples may be regarded as typical:
+     * Returns a string representation of this stack trace element.
+     *
+     * @apiNote The format of this string depends on the implementation, but the
+     * following examples may be regarded as typical:
      * <ul>
      * <li>
      *     "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101)}"
@@ -309,7 +314,7 @@
      * then the second element is omitted as shown in
      * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}".
      *
-     * If the class loader is a <a href="ClassLoader.html#builtinLoaders">
+     * <p> If the class loader is a <a href="ClassLoader.html#builtinLoaders">
      * built-in class loader</a> or is not named then the first element
      * and its following {@code "/"} are omitted as shown in
      * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}".
@@ -317,25 +322,30 @@
      * the second element and its following {@code "/"} are also omitted
      * as shown in "{@code MyClass.mash(MyClass.java:9)}".
      *
+     * <p> The {@code toString} method may return two different values on two
+     * {@code StackTraceElement} instances that are
+     * {@linkplain #equals(Object) equal}, for example one created via the
+     * constructor, and one obtained from {@link java.lang.Throwable} or
+     * {@link java.lang.StackWalker.StackFrame}, where an implementation may
+     * choose to omit some element in the returned string.
+     *
      * @see    Throwable#printStackTrace()
      */
     public String toString() {
-        String s = buildLoaderModuleClassName();
-        if (s == null) {
-            // all elements will be included
-            s = "";
-            if (classLoaderName != null && !classLoaderName.isEmpty()) {
-                s += classLoaderName + "/";
+        String s = "";
+        if (!dropClassLoaderName() && classLoaderName != null &&
+                !classLoaderName.isEmpty()) {
+            s += classLoaderName + "/";
+        }
+        if (moduleName != null && !moduleName.isEmpty()) {
+            s += moduleName;
+
+            if (!dropModuleVersion() && moduleVersion != null &&
+                    !moduleVersion.isEmpty()) {
+                s += "@" + moduleVersion;
             }
-            if (moduleName != null && !moduleName.isEmpty()) {
-                s += moduleName;
-
-                if (moduleVersion != null && !moduleVersion.isEmpty()) {
-                    s += "@" + moduleVersion;
-                }
-            }
-            s = s.isEmpty() ? declaringClass : s + "/" + declaringClass;
         }
+        s = s.isEmpty() ? declaringClass : s + "/" + declaringClass;
 
         return s + "." + methodName + "(" +
              (isNativeMethod() ? "Native Method)" :
@@ -397,67 +407,53 @@
 
 
     /**
-     * Build the compacted String representation to be returned by
-     * toString method from the declaring Class object.
+     * Called from of() methods to set the 'format' bitmap using the Class
+     * reference stored in declaringClassObject, and then clear the reference.
+     *
+     * <p>
+     * If the module is a non-upgradeable JDK module, then set
+     * JDK_NON_UPGRADEABLE_MODULE to omit its version string.
+     * <p>
+     * If the loader is one of the built-in loaders (`boot`, `platform`, or `app`)
+     * then set BUILTIN_CLASS_LOADER to omit the first element (`<loader>/`).
      */
-    synchronized String buildLoaderModuleClassName() {
-        if (classOrLoaderModuleClassName == null)
-            return null;
+    private synchronized void computeFormat() {
+        try {
+            Class<?> cls = (Class<?>) declaringClassObject;
+            ClassLoader loader = cls.getClassLoader0();
+            Module m = cls.getModule();
+            byte bits = 0;
 
-        if (classOrLoaderModuleClassName instanceof Class) {
-            Class<?> cls = (Class<?>)classOrLoaderModuleClassName;
-            classOrLoaderModuleClassName = toLoaderModuleClassName(cls);
+            // First element - class loader name
+            // Call package-private ClassLoader::name method
+
+            if (loader instanceof BuiltinClassLoader) {
+                bits |= BUILTIN_CLASS_LOADER;
+            }
+
+            // Second element - module name and version
+
+            // Omit if is a JDK non-upgradeable module (recorded in the hashes
+            // in java.base)
+            if (isHashedInJavaBase(m)) {
+                bits |= JDK_NON_UPGRADEABLE_MODULE;
+            }
+            format = bits;
+        } finally {
+            // Class reference no longer needed, clear it
+            declaringClassObject = null;
         }
-        return (String)classOrLoaderModuleClassName;
     }
 
-    /**
-     * Returns <loader>/<module>/<fully-qualified-classname> string
-     * representation of the given class.
-     * <p>
-     * If the module is a non-upgradeable JDK module then omit
-     * its version string.
-     * <p>
-     * If the loader has no name, or if the loader is one of the built-in
-     * loaders (`boot`, `platform`, or `app`) then drop the first element
-     * (`<loader>/`).
-     * <p>
-     * If the first element has been dropped and the module is unnamed
-     * then drop the second element (`<module>/`).
-     * <p>
-     * If the first element is not dropped and the module is unnamed
-     * then drop `<module>`.
-     */
-    private static String toLoaderModuleClassName(Class<?> cls) {
-        ClassLoader loader = cls.getClassLoader0();
-        Module m = cls.getModule();
+    private static final byte BUILTIN_CLASS_LOADER       = 0x1;
+    private static final byte JDK_NON_UPGRADEABLE_MODULE = 0x2;
 
-        // First element - class loader name
-        // Call package-private ClassLoader::name method
-        String s = "";
-        if (loader != null && loader.name() != null &&
-                !(loader instanceof BuiltinClassLoader)) {
-            s = loader.name() + "/";
-        }
+    private boolean dropClassLoaderName() {
+        return (format & BUILTIN_CLASS_LOADER) == BUILTIN_CLASS_LOADER;
+    }
 
-        // Second element - module name and version
-        if (m != null && m.isNamed()) {
-            s += m.getName();
-            // Include version if it is a user module or upgradeable module
-            //
-            // If it is JDK non-upgradeable module which is recorded
-            // in the hashes in java.base, omit the version.
-            if (!isHashedInJavaBase(m)) {
-                Optional<Version> ov = m.getDescriptor().version();
-                if (ov.isPresent()) {
-                    String version = "@" + ov.get().toString();
-                    s += version;
-                }
-            }
-        }
-
-        // fully-qualified class name
-        return s.isEmpty() ? cls.getName() : s + "/" + cls.getName();
+    private boolean dropModuleVersion() {
+        return (format & JDK_NON_UPGRADEABLE_MODULE) == JDK_NON_UPGRADEABLE_MODULE;
     }
 
     /**
@@ -484,13 +480,16 @@
         static Set<String> HASHED_MODULES = hashedModules();
 
         static Set<String> hashedModules() {
-            Module javaBase = Layer.boot().findModule("java.base").get();
-            Optional<ModuleHashes> ohashes =
-                SharedSecrets.getJavaLangModuleAccess()
-                             .hashes(javaBase.getDescriptor());
 
-            if (ohashes.isPresent()) {
-                Set<String> names = new HashSet<>(ohashes.get().names());
+            Optional<ResolvedModule> resolvedModule = Layer.boot()
+                    .configuration()
+                    .findModule("java.base");
+            assert resolvedModule.isPresent();
+            ModuleReference mref = resolvedModule.get().reference();
+            assert mref instanceof ModuleReferenceImpl;
+            ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
+            if (hashes != null) {
+                Set<String> names = new HashSet<>(hashes.names());
                 names.add("java.base");
                 return names;
             }
@@ -519,7 +518,7 @@
 
         // ensure the proper StackTraceElement initialization
         for (StackTraceElement ste : stackTrace) {
-            ste.buildLoaderModuleClassName();
+            ste.computeFormat();
         }
         return stackTrace;
     }
@@ -531,7 +530,7 @@
         StackTraceElement ste = new StackTraceElement();
         initStackTraceElement(ste, sfi);
 
-        ste.buildLoaderModuleClassName();
+        ste.computeFormat();
         return ste;
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java	Mon Dec 19 09:16:40 2016 -0800
@@ -227,7 +227,9 @@
      * @return  the value <i>e</i><sup>{@code a}</sup>,
      *          where <i>e</i> is the base of the natural logarithms.
      */
-    public static native double exp(double a);
+    public static double exp(double a) {
+        return FdLibm.Exp.compute(a);
+    }
 
     /**
      * Returns the natural logarithm (base <i>e</i>) of a {@code double}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Dec 19 09:16:40 2016 -0800
@@ -172,6 +172,7 @@
      * @throws IllegalAccessException if the access check specified above fails
      * @throws SecurityException if denied by the security manager
      * @since 9
+     * @see Lookup#dropLookupMode
      */
     public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
         SecurityManager sm = System.getSecurityManager();
@@ -691,10 +692,15 @@
          *  A lookup object on a new lookup class
          *  {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
          *  may have some mode bits set to zero.
+         *  Mode bits can also be
+         *  {@linkplain java.lang.invoke.MethodHandles.Lookup#dropLookupMode directly cleared}.
+         *  Once cleared, mode bits cannot be restored from the downgraded lookup object.
          *  The purpose of this is to restrict access via the new lookup object,
          *  so that it can access only names which can be reached by the original
          *  lookup object, and also by the new lookup class.
          *  @return the lookup modes, which limit the kinds of access performed by this lookup object
+         *  @see #in
+         *  @see #dropLookupMode
          */
         public int lookupModes() {
             return allowedModes & ALL_MODES;
@@ -748,7 +754,8 @@
          * which may change due to this operation.
          *
          * @param requestedLookupClass the desired lookup class for the new lookup object
-         * @return a lookup object which reports the desired lookup class
+         * @return a lookup object which reports the desired lookup class, or the same object
+         * if there is no change
          * @throws NullPointerException if the argument is null
          */
         public Lookup in(Class<?> requestedLookupClass) {
@@ -788,6 +795,40 @@
             return new Lookup(requestedLookupClass, newModes);
         }
 
+
+        /**
+         * Creates a lookup on the same lookup class which this lookup object
+         * finds members, but with a lookup mode that has lost the given lookup mode.
+         * The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
+         * MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
+         * {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup
+         * mode will never have this access capability. When dropping {@code PACKAGE}
+         * then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE}
+         * access. When dropping {@code MODULE} then the resulting lookup will not
+         * have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code
+         * PUBLIC} is dropped then the resulting lookup has no access.
+         * @param modeToDrop the lookup mode to drop
+         * @return a lookup object which lacks the indicated mode, or the same object if there is no change
+         * @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
+         * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE}
+         * @since 9
+         * @see MethodHandles#privateLookupIn
+         */
+        public Lookup dropLookupMode(int modeToDrop) {
+            int oldModes = lookupModes();
+            int newModes = oldModes & ~(modeToDrop | PROTECTED);
+            switch (modeToDrop) {
+                case PUBLIC: newModes &= ~(ALL_MODES); break;
+                case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
+                case PACKAGE: newModes &= ~(PRIVATE); break;
+                case PROTECTED:
+                case PRIVATE: break;
+                default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
+            }
+            if (newModes == oldModes) return this;  // return self if no change
+            return new Lookup(lookupClass(), newModes);
+        }
+
         // Make sure outer class is initialized first.
         static { IMPL_NAMES.getClass(); }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Mon Dec 19 09:16:40 2016 -0800
@@ -29,7 +29,6 @@
 import java.io.IOException;
 import java.io.PrintStream;
 import java.io.UncheckedIOException;
-import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -38,7 +37,6 @@
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -52,7 +50,7 @@
 import static java.util.Objects.*;
 
 import jdk.internal.module.Checks;
-import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
 
 
 /**
@@ -123,8 +121,9 @@
 
         private final Set<Modifier> mods;
         private final String name;
+        private final Version compiledVersion;
 
-        private Requires(Set<Modifier> ms, String mn) {
+        private Requires(Set<Modifier> ms, String mn, Version v) {
             if (ms.isEmpty()) {
                 ms = Collections.emptySet();
             } else {
@@ -132,11 +131,13 @@
             }
             this.mods = ms;
             this.name = mn;
+            this.compiledVersion = v;
         }
 
-        private Requires(Set<Modifier> ms, String mn, boolean unused) {
+        private Requires(Set<Modifier> ms, String mn, Version v, boolean unused) {
             this.mods = ms;
             this.name = mn;
+            this.compiledVersion = v;
         }
 
         /**
@@ -158,12 +159,26 @@
         }
 
         /**
+         * Returns the version of the module if recorded at compile-time.
+         *
+         * @return The version of the module if recorded at compile-time
+         */
+        public Optional<Version> compiledVersion() {
+            return Optional.ofNullable(compiledVersion);
+        }
+
+        /**
          * Compares this module dependence to another.
          *
          * <p> Two {@code Requires} objects are compared by comparing their
          * module name lexicographically.  Where the module names are equal then
          * the sets of modifiers are compared based on a value computed from the
-         * ordinal of each modifier. </p>
+         * ordinal of each modifier. Where the module names are equal and the
+         * set of modifiers are equal then the version of the modules recorded
+         * at compile-time are compared. When comparing the versions recorded
+         * at compile-time then a dependence that has a recorded version is
+         * considered to succeed a dependence that does not have a recorded
+         * version. </p>
          *
          * @return A negative integer, zero, or a positive integer if this module
          *         dependence is less than, equal to, or greater than the given
@@ -174,8 +189,24 @@
             int c = this.name().compareTo(that.name());
             if (c != 0)
                 return c;
-            // same name, compare by modifiers
-            return Long.compare(this.modsValue(), that.modsValue());
+
+            // modifiers
+            c = Long.compare(this.modsValue(), that.modsValue());
+            if (c != 0)
+                return c;
+
+            // compiledVersion
+            if (this.compiledVersion != null) {
+                if (that.compiledVersion != null)
+                    c = this.compiledVersion.compareTo(that.compiledVersion);
+                else
+                    c = 1;
+            } else {
+                if (that.compiledVersion != null)
+                    c = -1;
+            }
+
+            return c;
         }
 
         /**
@@ -195,7 +226,9 @@
          *
          * <p> If the given object is not a {@code Requires} then this method
          * returns {@code false}. Two module dependence objects are equal if
-         * the module names are equal and set of modifiers are equal. </p>
+         * the module names are equal, set of modifiers are equal, and the
+         * compiled version of both modules is equal or not recorded for
+         * both modules. </p>
          *
          * <p> This method satisfies the general contract of the {@link
          * java.lang.Object#equals(Object) Object.equals} method. </p>
@@ -211,21 +244,25 @@
             if (!(ob instanceof Requires))
                 return false;
             Requires that = (Requires)ob;
-            return (name.equals(that.name) && mods.equals(that.mods));
+            return name.equals(that.name) && mods.equals(that.mods)
+                    && Objects.equals(compiledVersion, that.compiledVersion);
         }
 
         /**
          * Computes a hash code for this module dependence.
          *
-         * <p> The hash code is based upon the module name and modifiers. It
-         * satisfies the general contract of the {@link Object#hashCode
-         * Object.hashCode} method. </p>
+         * <p> The hash code is based upon the module name, modifiers, and the
+         * module version if recorded at compile time. It satisfies the general
+         * contract of the {@link Object#hashCode Object.hashCode} method. </p>
          *
          * @return The hash-code value for this module dependence
          */
         @Override
         public int hashCode() {
-            return name.hashCode() * 43 + mods.hashCode();
+            int hash = name.hashCode() * 43 + mods.hashCode();
+            if (compiledVersion != null)
+                hash = hash * 43 + compiledVersion.hashCode();
+            return hash;
         }
 
         /**
@@ -235,7 +272,13 @@
          */
         @Override
         public String toString() {
-            return ModuleDescriptor.toString(mods, name);
+            String what;
+            if (compiledVersion != null) {
+                what = name() + " (@" + compiledVersion + ")";
+            } else {
+                what = name();
+            }
+            return ModuleDescriptor.toString(mods, what);
         }
     }
 
@@ -967,9 +1010,8 @@
     }
 
 
-
-    // From module declarations
     private final String name;
+    private final Version version;
     private final boolean open;
 
     // Indicates if synthesised for a JAR file found on the module path
@@ -984,17 +1026,16 @@
     private final Set<String> uses;
     private final Set<Provides> provides;
 
-    // "Extended" information, added post-compilation by tools
-    private final Version version;
+    // Added post-compilation by tools
+    private final Set<String> packages;
     private final String mainClass;
     private final String osName;
     private final String osArch;
     private final String osVersion;
-    private final Set<String> packages;
-    private final ModuleHashes hashes;
 
 
     private ModuleDescriptor(String name,
+                             Version version,
                              boolean open,
                              boolean automatic,
                              boolean synthetic,
@@ -1003,16 +1044,14 @@
                              Set<Opens> opens,
                              Set<String> uses,
                              Set<Provides> provides,
-                             Version version,
+                             Set<String> packages,
                              String mainClass,
                              String osName,
                              String osArch,
-                             String osVersion,
-                             Set<String> packages,
-                             ModuleHashes hashes)
+                             String osVersion)
     {
-
         this.name = name;
+        this.version = version;
         this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
@@ -1020,18 +1059,16 @@
         assert (requires.stream().map(Requires::name).distinct().count()
                 == requires.size());
         this.requires = emptyOrUnmodifiableSet(requires);
-
         this.exports = emptyOrUnmodifiableSet(exports);
         this.opens = emptyOrUnmodifiableSet(opens);
         this.uses = emptyOrUnmodifiableSet(uses);
         this.provides = emptyOrUnmodifiableSet(provides);
-        this.version = version;
+
+        this.packages = emptyOrUnmodifiableSet(packages);
         this.mainClass = mainClass;
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
-        this.hashes = hashes;
-        this.packages = emptyOrUnmodifiableSet(packages);
     }
 
     /**
@@ -1039,6 +1076,7 @@
      */
     ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
         this.name = md.name;
+        this.version = md.version;
         this.open = md.open;
         this.automatic = md.automatic;
         this.synthetic = md.synthetic;
@@ -1049,16 +1087,14 @@
         this.uses = md.uses;
         this.provides = md.provides;
 
-        this.version = md.version;
+        Set<String> packages = new HashSet<>(md.packages);
+        packages.addAll(pkgs);
+        this.packages = emptyOrUnmodifiableSet(packages);
+
         this.mainClass = md.mainClass;
         this.osName = md.osName;
         this.osArch = md.osArch;
         this.osVersion = md.osVersion;
-        this.hashes = null; // need to ignore
-
-        Set<String> packages = new HashSet<>(md.packages);
-        packages.addAll(pkgs);
-        this.packages = emptyOrUnmodifiableSet(packages);
     }
 
     /**
@@ -1066,6 +1102,7 @@
      * The arguments are pre-validated and sets are unmodifiable sets.
      */
     ModuleDescriptor(String name,
+                     Version version,
                      boolean open,
                      boolean automatic,
                      boolean synthetic,
@@ -1074,16 +1111,15 @@
                      Set<Opens> opens,
                      Set<String> uses,
                      Set<Provides> provides,
-                     Version version,
+                     Set<String> packages,
                      String mainClass,
                      String osName,
                      String osArch,
                      String osVersion,
-                     Set<String> packages,
-                     ModuleHashes hashes,
                      int hashCode,
                      boolean unused) {
         this.name = name;
+        this.version = version;
         this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
@@ -1093,12 +1129,10 @@
         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;
     }
 
@@ -1284,13 +1318,6 @@
         return packages;
     }
 
-    /**
-     * Returns the object with the hashes of other modules
-     */
-    Optional<ModuleHashes> hashes() {
-        return Optional.ofNullable(hashes);
-    }
-
 
     /**
      * A builder used for building {@link ModuleDescriptor} objects.
@@ -1317,15 +1344,13 @@
     public static final class Builder {
         final String name;
         final boolean strict; // true if module names are checked
-        boolean open;
+        final boolean open;
+        final boolean synthetic;
         boolean automatic;
-        boolean synthetic;
         final Map<String, Requires> requires = new HashMap<>();
-
         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<>();
         Version version;
@@ -1333,7 +1358,6 @@
         String osArch;
         String osVersion;
         String mainClass;
-        ModuleHashes hashes;
 
         /**
          * Initializes a new builder with the given module name.
@@ -1341,14 +1365,11 @@
          * @param strict
          *        Indicates whether module names are checked or not
          */
-        Builder(String name, boolean strict) {
+        Builder(String name, boolean strict, boolean open, boolean synthetic) {
+            this.name = (strict) ? requireModuleName(name) : name;
             this.strict = strict;
-            this.name = (strict) ? requireModuleName(name) : name;
-        }
-
-        /* package */ Builder open(boolean open) {
             this.open = open;
-            return this;
+            this.synthetic = synthetic;
         }
 
         /* package */ Builder automatic(boolean automatic) {
@@ -1356,10 +1377,20 @@
             return this;
         }
 
-        /* package */ boolean isOpen() { return open; }
+        /**
+         * Returns the set of packages that are exported (unconditionally or
+         * unconditionally).
+         */
+        /* package */ Set<String> exportedPackages() {
+            return exports.keySet();
+        }
 
-        /* package */ boolean isAutomatic() {
-            return automatic;
+        /**
+         * Returns the set of packages that are opened (unconditionally or
+         * unconditionally).
+         */
+        /* package */Set<String> openPackages() {
+            return opens.keySet();
         }
 
         /**
@@ -1389,6 +1420,36 @@
 
         /**
          * Adds a dependence on a module with the given (and possibly empty)
+         * set of modifiers. The dependence includes the version of the
+         * module that that was recorded at compile-time.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  mn
+         *         The module name
+         * @param  compiledVersion
+         *         The version of the module recorded at compile-time
+         *
+         * @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(Set<Requires.Modifier> ms,
+                                String mn,
+                                Version compiledVersion) {
+            Objects.requireNonNull(compiledVersion);
+            if (strict)
+                mn = requireModuleName(mn);
+            return requires(new Requires(ms, mn, compiledVersion));
+        }
+
+        /**
+         * Adds a dependence on a module with the given (and possibly empty)
          * set of modifiers.
          *
          * @param  ms
@@ -1408,7 +1469,7 @@
         public Builder requires(Set<Requires.Modifier> ms, String mn) {
             if (strict)
                 mn = requireModuleName(mn);
-            return requires(new Requires(ms, mn));
+            return requires(new Requires(ms, mn, null));
         }
 
         /**
@@ -1705,17 +1766,6 @@
             return opens(Collections.emptySet(), pn);
         }
 
-
-        // Used by ModuleInfo, after a packageFinder is invoked
-        /* 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.
          *
@@ -1789,7 +1839,6 @@
             if (providerNames.isEmpty())
                 throw new IllegalArgumentException("Empty providers set");
             providerNames.forEach(Checks::requireServiceProviderName);
-
             provides.put(service, p);
             return this;
         }
@@ -1914,7 +1963,7 @@
          *         If {@code mainClass} is null or is not a legal Java identifier
          */
         public Builder mainClass(String mc) {
-            mainClass = requireJavaIdentifier("main class name", mc);
+            mainClass = requireBinaryName("main class name", mc);
             return this;
         }
 
@@ -1972,16 +2021,6 @@
             return this;
         }
 
-        /* package */ Builder hashes(ModuleHashes hashes) {
-            this.hashes = hashes;
-            return this;
-        }
-
-        /* package */ Builder synthetic(boolean v) {
-            this.synthetic = v;
-            return this;
-        }
-
         /**
          * Builds and returns a {@code ModuleDescriptor} from its components.
          *
@@ -1990,7 +2029,9 @@
         public ModuleDescriptor build() {
             Set<Requires> requires = new HashSet<>(this.requires.values());
 
-            Set<String> packages = new HashSet<>(exportedAndOpenPackages());
+            Set<String> packages = new HashSet<>();
+            packages.addAll(exports.keySet());
+            packages.addAll(opens.keySet());
             packages.addAll(concealedPackages);
 
             Set<Exports> exports = new HashSet<>(this.exports.values());
@@ -1999,6 +2040,7 @@
             Set<Provides> provides = new HashSet<>(this.provides.values());
 
             return new ModuleDescriptor(name,
+                                        version,
                                         open,
                                         automatic,
                                         synthetic,
@@ -2007,13 +2049,11 @@
                                         opens,
                                         uses,
                                         provides,
-                                        version,
+                                        packages,
                                         mainClass,
                                         osName,
                                         osArch,
-                                        osVersion,
-                                        packages,
-                                        hashes);
+                                        osVersion);
         }
 
     }
@@ -2088,8 +2128,7 @@
                 && Objects.equals(osName, that.osName)
                 && Objects.equals(osArch, that.osArch)
                 && Objects.equals(osVersion, that.osVersion)
-                && Objects.equals(packages, that.packages)
-                && Objects.equals(hashes, that.hashes));
+                && Objects.equals(packages, that.packages));
     }
 
     private transient int hash;  // cached hash code
@@ -2122,7 +2161,6 @@
             hc = hc * 43 + Objects.hashCode(osArch);
             hc = hc * 43 + Objects.hashCode(osVersion);
             hc = hc * 43 + Objects.hashCode(packages);
-            hc = hc * 43 + Objects.hashCode(hashes);
             if (hc == 0)
                 hc = -1;
             hash = hc;
@@ -2145,7 +2183,7 @@
         if (!requires.isEmpty())
             sb.append(", ").append(requires);
         if (!uses.isEmpty())
-            sb.append(", ").append(uses);
+            sb.append(", uses: ").append(uses);
         if (!exports.isEmpty())
             sb.append(", exports: ").append(exports);
         if (!opens.isEmpty())
@@ -2171,7 +2209,7 @@
      *         identifier
      */
     public static Builder module(String name) {
-        return new Builder(name, true);
+        return new Builder(name, true, false, false);
     }
 
     /**
@@ -2199,7 +2237,7 @@
      *         identifier
      */
     public static Builder openModule(String name) {
-        return new Builder(name, true).open(true);
+        return new Builder(name, true, true, false);
     }
 
     /**
@@ -2221,7 +2259,7 @@
      * @see ModuleFinder#of(Path[])
      */
     public static Builder automaticModule(String name) {
-        return new Builder(name, true).automatic(true);
+        return new Builder(name, true, false, false).automatic(true);
     }
 
 
@@ -2263,7 +2301,7 @@
                                         Supplier<Set<String>> packageFinder)
         throws IOException
     {
-        return ModuleInfo.read(in, requireNonNull(packageFinder));
+        return ModuleInfo.read(in, requireNonNull(packageFinder)).descriptor();
     }
 
     /**
@@ -2281,7 +2319,7 @@
      *         If an I/O error occurs reading from the input stream
      */
     public static ModuleDescriptor read(InputStream in) throws IOException {
-        return ModuleInfo.read(in, null);
+        return ModuleInfo.read(in, null).descriptor();
     }
 
     /**
@@ -2320,7 +2358,7 @@
     public static ModuleDescriptor read(ByteBuffer bb,
                                         Supplier<Set<String>> packageFinder)
     {
-        return ModuleInfo.read(bb, requireNonNull(packageFinder));
+        return ModuleInfo.read(bb, requireNonNull(packageFinder)).descriptor();
     }
 
     /**
@@ -2336,7 +2374,7 @@
      *         If an invalid module descriptor is detected
      */
     public static ModuleDescriptor read(ByteBuffer bb) {
-        return ModuleInfo.read(bb, null);
+        return ModuleInfo.read(bb, null).descriptor();
     }
 
     private static <K,V> Map<K,V> emptyOrUnmodifiableMap(Map<K,V> map) {
@@ -2377,18 +2415,26 @@
         jdk.internal.misc.SharedSecrets
             .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
                 @Override
-                public Builder newModuleBuilder(String mn, boolean strict) {
-                    return new Builder(mn, strict);
+                public Builder newModuleBuilder(String mn,
+                                                boolean strict,
+                                                boolean open,
+                                                boolean synthetic) {
+                    return new Builder(mn, strict, open, synthetic);
                 }
 
                 @Override
-                public Builder newOpenModuleBuilder(String mn, boolean strict) {
-                    return new Builder(mn, strict).open(true);
+                public Set<String> exportedPackages(ModuleDescriptor.Builder builder) {
+                    return builder.exportedPackages();
                 }
 
                 @Override
-                public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
-                    return new Requires(ms, mn, true);
+                public Set<String> openPackages(ModuleDescriptor.Builder builder) {
+                    return builder.openPackages();
+                }
+
+                @Override
+                public Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v) {
+                    return new Requires(ms, mn, v, true);
                 }
 
                 @Override
@@ -2433,6 +2479,7 @@
 
                 @Override
                 public ModuleDescriptor newModuleDescriptor(String name,
+                                                            Version version,
                                                             boolean open,
                                                             boolean automatic,
                                                             boolean synthetic,
@@ -2441,15 +2488,14 @@
                                                             Set<Opens> opens,
                                                             Set<String> uses,
                                                             Set<Provides> provides,
-                                                            Version version,
+                                                            Set<String> packages,
                                                             String mainClass,
                                                             String osName,
                                                             String osArch,
                                                             String osVersion,
-                                                            Set<String> packages,
-                                                            ModuleHashes hashes,
                                                             int hashCode) {
                     return new ModuleDescriptor(name,
+                                                version,
                                                 open,
                                                 automatic,
                                                 synthetic,
@@ -2458,23 +2504,16 @@
                                                 opens,
                                                 uses,
                                                 provides,
-                                                version,
+                                                packages,
                                                 mainClass,
                                                 osName,
                                                 osArch,
                                                 osVersion,
-                                                packages,
-                                                hashes,
                                                 hashCode,
                                                 false);
                 }
 
                 @Override
-                public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
-                    return descriptor.hashes();
-                }
-
-                @Override
                 public Configuration resolveRequiresAndUses(ModuleFinder finder,
                                                             Collection<String> roots,
                                                             boolean check,
@@ -2482,20 +2521,6 @@
                 {
                     return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
                 }
-
-                @Override
-                public ModuleReference newPatchedModule(ModuleDescriptor descriptor,
-                                                        URI location,
-                                                        Supplier<ModuleReader> s) {
-                    return new ModuleReference(descriptor, location, s, true, null);
-                }
-
-                @Override
-                public ModuleFinder newModulePath(Runtime.Version version,
-                                                  boolean isLinkPhase,
-                                                  Path... entries) {
-                    return new ModulePath(version, isLinkPhase, entries);
-                }
             });
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Mon Dec 19 09:16:40 2016 -0800
@@ -42,6 +42,8 @@
 import java.util.Optional;
 import java.util.Set;
 
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.SystemModuleFinder;
 import sun.security.action.GetPropertyAction;
 
 /**
@@ -137,7 +139,7 @@
 
     /**
      * Returns a module finder that locates the <em>system modules</em>. The
-     * system modules are typically linked into the Java run-time image.
+     * system modules are the modules in the Java run-time image.
      * The module finder will always find {@code java.base}.
      *
      * <p> If there is a security manager set then its {@link
@@ -166,7 +168,7 @@
 
         Path modules = Paths.get(home, "lib", "modules");
         if (Files.isRegularFile(modules)) {
-            return new SystemModuleFinder();
+            return SystemModuleFinder.getInstance();
         } else {
             Path mlib = Paths.get(home, "modules");
             if (Files.isDirectory(mlib)) {
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,899 +0,0 @@
-/*
- * 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
- * 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.io.DataInput;
-import java.io.DataInputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-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.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes;
-
-import static jdk.internal.module.ClassFileConstants.*;
-
-
-/**
- * Read module information from a {@code module-info} class file.
- *
- * @implNote The rationale for the hand-coded reader is startup performance
- * and fine control over the throwing of InvalidModuleDescriptorException.
- */
-
-final class ModuleInfo {
-
-    // supplies the set of packages when ModulePackages attribute not present
-    private final Supplier<Set<String>> packageFinder;
-
-    // indicates if the ModuleHashes attribute should be parsed
-    private final boolean parseHashes;
-
-    private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
-        packageFinder = pf;
-        parseHashes = ph;
-    }
-
-    private ModuleInfo(Supplier<Set<String>> pf) {
-        this(pf, true);
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given input stream.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws IOException
-     */
-    public static ModuleDescriptor read(InputStream in,
-                                        Supplier<Set<String>> pf)
-        throws IOException
-    {
-        try {
-            return new ModuleInfo(pf).doRead(new DataInputStream(in));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        }
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given byte buffer.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws UncheckedIOException
-     */
-    public static ModuleDescriptor read(ByteBuffer bb,
-                                        Supplier<Set<String>> pf)
-    {
-        try {
-            return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given byte buffer
-     * but ignore the {@code ModuleHashes} attribute.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws UncheckedIOException
-     */
-    static ModuleDescriptor readIgnoringHashes(ByteBuffer bb,
-                                               Supplier<Set<String>> pf)
-    {
-        try {
-            return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-    }
-
-    /**
-     * Reads the input as a module-info class file.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
-     *         because an identifier is not a legal Java identifier, duplicate
-     *         exports, and many other reasons
-     */
-    private ModuleDescriptor doRead(DataInput in) throws IOException {
-
-        int magic = in.readInt();
-        if (magic != 0xCAFEBABE)
-            throw invalidModuleDescriptor("Bad magic number");
-
-        int minor_version = in.readUnsignedShort();
-        int major_version = in.readUnsignedShort();
-        if (major_version < 53) {
-            throw invalidModuleDescriptor("Must be >= 53.0");
-        }
-
-        ConstantPool cpool = new ConstantPool(in);
-
-        int access_flags = in.readUnsignedShort();
-        if (access_flags != ACC_MODULE)
-            throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
-
-        int this_class = in.readUnsignedShort();
-        if (this_class != 0)
-            throw invalidModuleDescriptor("this_class must be 0");
-
-        int super_class = in.readUnsignedShort();
-        if (super_class > 0)
-            throw invalidModuleDescriptor("bad #super_class");
-
-        int interfaces_count = in.readUnsignedShort();
-        if (interfaces_count > 0)
-            throw invalidModuleDescriptor("Bad #interfaces");
-
-        int fields_count = in.readUnsignedShort();
-        if (fields_count > 0)
-            throw invalidModuleDescriptor("Bad #fields");
-
-        int methods_count = in.readUnsignedShort();
-        if (methods_count > 0)
-            throw invalidModuleDescriptor("Bad #methods");
-
-        int attributes_count = in.readUnsignedShort();
-
-        // 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);
-            int length = in.readInt();
-
-            boolean added = attributes.add(attribute_name);
-            if (!added && isAttributeAtMostOnce(attribute_name)) {
-                throw invalidModuleDescriptor("More than one "
-                                              + attribute_name + " attribute");
-            }
-
-            switch (attribute_name) {
-
-                case MODULE :
-                    builder = readModuleAttribute(in, cpool);
-                    break;
-
-                case MODULE_PACKAGES :
-                    packages = readModulePackagesAttribute(in, cpool);
-                    break;
-
-                case MODULE_VERSION :
-                    version = readModuleVersionAttribute(in, cpool);
-                    break;
-
-                case MODULE_MAIN_CLASS :
-                    mainClass = readModuleMainClassAttribute(in, cpool);
-                    break;
-
-                case MODULE_TARGET :
-                    osValues = readModuleTargetAttribute(in, cpool);
-                    break;
-
-                case MODULE_HASHES :
-                    if (parseHashes) {
-                        hashes = readModuleHashesAttribute(in, cpool);
-                    } else {
-                        in.skipBytes(length);
-                    }
-                    break;
-
-                default:
-                    if (isAttributeDisallowed(attribute_name)) {
-                        throw invalidModuleDescriptor(attribute_name
-                                                      + " attribute not allowed");
-                    } else {
-                        in.skipBytes(length);
-                    }
-
-            }
-        }
-
-        // the Module attribute is required
-        if (builder == null) {
-            throw invalidModuleDescriptor(MODULE + " attribute not found");
-        }
-
-        // 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 {
-                packages = new HashSet<>(packageFinder.get());
-            } catch (UncheckedIOException x) {
-                throw x.getCause();
-            }
-            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);
-        }
-
-        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, returning the ModuleDescriptor.Builder to
-     * build the corresponding ModuleDescriptor.
-     */
-    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.getUtf8AsBinaryName(index);
-            Set<Requires.Modifier> mods;
-            if (flags == 0) {
-                mods = Collections.emptySet();
-            } else {
-                mods = new HashSet<>();
-                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(Requires.Modifier.SYNTHETIC);
-                if ((flags & ACC_MANDATED) != 0)
-                    mods.add(Requires.Modifier.MANDATED);
-            }
-            builder.requires(mods, dn);
-            if (dn.equals("java.base"))
-                requiresJavaBase = true;
-        }
-        if (mn.equals("java.base")) {
-            if (requires_count > 0) {
-                throw invalidModuleDescriptor("The requires table for java.base"
-                                              + " must be 0 length");
-            }
-        } else if (!requiresJavaBase) {
-            throw invalidModuleDescriptor("The requires table must have"
-                                          + " an entry for java.base");
-        }
-
-        int exports_count = in.readUnsignedShort();
-        if (exports_count > 0) {
-            for (int i=0; i<exports_count; i++) {
-                int index = in.readUnsignedShort();
-                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.getUtf8AsBinaryName(exports_to_index));
-                    }
-                    builder.exports(mods, pkg, targets);
-                } else {
-                    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);
-                }
-            }
-        }
-
-        int uses_count = in.readUnsignedShort();
-        if (uses_count > 0) {
-            for (int i=0; i<uses_count; i++) {
-                int index = in.readUnsignedShort();
-                String sn = cpool.getClassNameAsBinaryName(index);
-                builder.uses(sn);
-            }
-        }
-
-        int provides_count = in.readUnsignedShort();
-        if (provides_count > 0) {
-            for (int i=0; i<provides_count; i++) {
-                int index = in.readUnsignedShort();
-                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);
-                }
-                builder.provides(sn, providers);
-            }
-        }
-
-        return builder;
-    }
-
-    /**
-     * Reads the ModulePackages attribute
-     */
-    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.getUtf8AsBinaryName(index);
-            packages.add(pn);
-        }
-        return packages;
-    }
-
-    /**
-     * Reads the ModuleVersion attribute
-     */
-    private String readModuleVersionAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int index = in.readUnsignedShort();
-        return cpool.getUtf8(index);
-    }
-
-    /**
-     * Reads the ModuleMainClass attribute
-     */
-    private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int index = in.readUnsignedShort();
-        return cpool.getClassNameAsBinaryName(index);
-    }
-
-    /**
-     * Reads the ModuleTarget attribute
-     */
-    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        String[] values = new String[3];
-
-        int name_index = in.readUnsignedShort();
-        if (name_index != 0)
-            values[0] = cpool.getUtf8(name_index);
-
-        int arch_index = in.readUnsignedShort();
-        if (arch_index != 0)
-            values[1] = cpool.getUtf8(arch_index);
-
-        int version_index = in.readUnsignedShort();
-        if (version_index != 0)
-            values[2] = cpool.getUtf8(version_index);
-
-        return values;
-    }
-
-
-    /**
-     * Reads the ModuleHashes attribute
-     */
-    private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int algorithm_index = in.readUnsignedShort();
-        String algorithm = cpool.getUtf8(algorithm_index);
-
-        int hash_count = in.readUnsignedShort();
-        Map<String, byte[]> map = new HashMap<>(hash_count);
-        for (int i=0; i<hash_count; i++) {
-            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);
-        }
-
-        return new ModuleHashes(algorithm, map);
-    }
-
-
-    /**
-     * Returns true if the given attribute can be present at most once
-     * in the class file. Returns false otherwise.
-     */
-    private static boolean isAttributeAtMostOnce(String name) {
-
-        if (name.equals(MODULE) ||
-                name.equals(SOURCE_FILE) ||
-                name.equals(SDE) ||
-                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;
-    }
-
-    /**
-     * 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, 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;
-        if (notAllowed == null) {
-            notAllowed = Set.of(
-                    "ConstantValue",
-                    "Code",
-                    "StackMapTable",
-                    "Exceptions",
-                    "EnclosingMethod",
-                    "Signature",
-                    "LineNumberTable",
-                    "LocalVariableTable",
-                    "LocalVariableTypeTable",
-                    "RuntimeVisibleParameterAnnotations",
-                    "RuntimeInvisibleParameterAnnotations",
-                    "RuntimeVisibleTypeAnnotations",
-                    "RuntimeInvisibleTypeAnnotations",
-                    "Synthetic",
-                    "AnnotationDefault",
-                    "BootstrapMethods",
-                    "MethodParameters");
-            predefinedNotAllowed = notAllowed;
-        }
-        return notAllowed.contains(name);
-    }
-
-    // lazily created set the pre-defined attributes that are not allowed
-    private static volatile Set<String> predefinedNotAllowed;
-
-
-    /**
-     * The constant pool in a class file.
-     */
-    private static class ConstantPool {
-        static final int CONSTANT_Utf8 = 1;
-        static final int CONSTANT_Integer = 3;
-        static final int CONSTANT_Float = 4;
-        static final int CONSTANT_Long = 5;
-        static final int CONSTANT_Double = 6;
-        static final int CONSTANT_Class = 7;
-        static final int CONSTANT_String = 8;
-        static final int CONSTANT_Fieldref = 9;
-        static final int CONSTANT_Methodref = 10;
-        static final int CONSTANT_InterfaceMethodref = 11;
-        static final int CONSTANT_NameAndType = 12;
-        static final int CONSTANT_MethodHandle = 15;
-        static final int CONSTANT_MethodType = 16;
-        static final int CONSTANT_InvokeDynamic = 18;
-
-        private static class Entry {
-            protected Entry(int tag) {
-                this.tag = tag;
-            }
-            final int tag;
-        }
-
-        private static class IndexEntry extends Entry {
-            IndexEntry(int tag, int index) {
-                super(tag);
-                this.index = index;
-            }
-            final int index;
-        }
-
-        private static class Index2Entry extends Entry {
-            Index2Entry(int tag, int index1, int index2) {
-                super(tag);
-                this.index1 = index1;
-                this.index2 = index2;
-            }
-            final int index1,  index2;
-        }
-
-        private static class ValueEntry extends Entry {
-            ValueEntry(int tag, Object value) {
-                super(tag);
-                this.value = value;
-            }
-            final Object value;
-        }
-
-        final Entry[] pool;
-
-        ConstantPool(DataInput in) throws IOException {
-            int count = in.readUnsignedShort();
-            pool = new Entry[count];
-
-            for (int i = 1; i < count; i++) {
-                int tag = in.readUnsignedByte();
-                switch (tag) {
-
-                    case CONSTANT_Utf8:
-                        String svalue = in.readUTF();
-                        pool[i] = new ValueEntry(tag, svalue);
-                        break;
-
-                    case CONSTANT_Class:
-                    case CONSTANT_String:
-                        int index = in.readUnsignedShort();
-                        pool[i] = new IndexEntry(tag, index);
-                        break;
-
-                    case CONSTANT_Double:
-                        double dvalue = in.readDouble();
-                        pool[i] = new ValueEntry(tag, dvalue);
-                        i++;
-                        break;
-
-                    case CONSTANT_Fieldref:
-                    case CONSTANT_InterfaceMethodref:
-                    case CONSTANT_Methodref:
-                    case CONSTANT_InvokeDynamic:
-                    case CONSTANT_NameAndType:
-                        int index1 = in.readUnsignedShort();
-                        int index2 = in.readUnsignedShort();
-                        pool[i] = new Index2Entry(tag, index1, index2);
-                        break;
-
-                    case CONSTANT_MethodHandle:
-                        int refKind = in.readUnsignedByte();
-                        index = in.readUnsignedShort();
-                        pool[i] = new Index2Entry(tag, refKind, index);
-                        break;
-
-                    case CONSTANT_MethodType:
-                        index = in.readUnsignedShort();
-                        pool[i] = new IndexEntry(tag, index);
-                        break;
-
-                    case CONSTANT_Float:
-                        float fvalue = in.readFloat();
-                        pool[i] = new ValueEntry(tag, fvalue);
-                        break;
-
-                    case CONSTANT_Integer:
-                        int ivalue = in.readInt();
-                        pool[i] = new ValueEntry(tag, ivalue);
-                        break;
-
-                    case CONSTANT_Long:
-                        long lvalue = in.readLong();
-                        pool[i] = new ValueEntry(tag, lvalue);
-                        i++;
-                        break;
-
-                    default:
-                        throw invalidModuleDescriptor("Bad constant pool entry: "
-                                                      + i);
-                }
-            }
-        }
-
-        String getClassName(int index) {
-            checkIndex(index);
-            Entry e = pool[index];
-            if (e.tag != CONSTANT_Class) {
-                throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
-                                              + index);
-            }
-            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];
-            if (e.tag != CONSTANT_Utf8) {
-                throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
-                                              + index);
-            }
-            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 DataInput implementation that reads from a ByteBuffer.
-     */
-    private static class DataInputWrapper implements DataInput {
-        private final ByteBuffer bb;
-
-        DataInputWrapper(ByteBuffer bb) {
-            this.bb = bb;
-        }
-
-        @Override
-        public void readFully(byte b[]) throws IOException {
-            readFully(b, 0, b.length);
-        }
-
-        @Override
-        public void readFully(byte b[], int off, int len) throws IOException {
-            try {
-                bb.get(b, off, len);
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int skipBytes(int n) {
-            int skip = Math.min(n, bb.remaining());
-            bb.position(bb.position() + skip);
-            return skip;
-        }
-
-        @Override
-        public boolean readBoolean() throws IOException {
-            try {
-                int ch = bb.get();
-                return (ch != 0);
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public byte readByte() throws IOException {
-            try {
-                return bb.get();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readUnsignedByte() throws IOException {
-            try {
-                return ((int) bb.get()) & 0xff;
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public short readShort() throws IOException {
-            try {
-                return bb.getShort();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readUnsignedShort() throws IOException {
-            try {
-                return ((int) bb.getShort()) & 0xffff;
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public char readChar() throws IOException {
-            try {
-                return bb.getChar();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readInt() throws IOException {
-            try {
-                return bb.getInt();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public long readLong() throws IOException {
-            try {
-                return bb.getLong();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public float readFloat() throws IOException {
-            try {
-                return bb.getFloat();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public double readDouble() throws IOException {
-            try {
-                return bb.getDouble();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public String readLine() {
-            throw new RuntimeException("not implemented");
-        }
-
-        @Override
-        public String readUTF() throws IOException {
-            // ### Need to measure the performance and feasibility of using
-            // the UTF-8 decoder instead.
-            return DataInputStream.readUTF(this);
-        }
-    }
-
-    /**
-     * Returns an InvalidModuleDescriptorException with the given detail
-     * message
-     */
-    private static InvalidModuleDescriptorException
-    invalidModuleDescriptor(String msg) {
-        return new InvalidModuleDescriptorException(msg);
-    }
-
-    /**
-     * Returns an InvalidModuleDescriptorException with a detail message to
-     * indicate that the class file is truncated.
-     */
-    private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
-        return invalidModuleDescriptor("Truncated module-info.class");
-    }
-
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,681 +0,0 @@
-/*
- * 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
- * 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.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Requires;
-import java.net.URI;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-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.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.zip.ZipFile;
-
-import jdk.internal.jmod.JmodFile;
-import jdk.internal.jmod.JmodFile.Section;
-import jdk.internal.module.Checks;
-import jdk.internal.perf.PerfCounter;
-import jdk.internal.util.jar.VersionedStream;
-
-
-/**
- * A {@code ModuleFinder} that locates modules on the file system by searching
- * a sequence of directories or packaged modules.
- *
- * The {@code ModuleFinder} can be created to work in either the run-time
- * or link-time phases. In both cases it locates modular JAR and exploded
- * modules. When created for link-time then it additionally locates
- * modules in JMOD files.
- */
-
-class ModulePath implements ModuleFinder {
-    private static final String MODULE_INFO = "module-info.class";
-
-    // the version to use for multi-release modular JARs
-    private final Runtime.Version releaseVersion;
-
-    // true for the link phase (supports modules packaged in JMOD format)
-    private final boolean isLinkPhase;
-
-    // the entries on this module path
-    private final Path[] entries;
-    private int next;
-
-    // map of module name to module reference map for modules already located
-    private final Map<String, ModuleReference> cachedModules = new HashMap<>();
-
-    ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
-        this.releaseVersion = version;
-        this.isLinkPhase = isLinkPhase;
-        this.entries = entries.clone();
-        for (Path entry : this.entries) {
-            Objects.requireNonNull(entry);
-        }
-    }
-
-    ModulePath(Path... entries) {
-        this(JarFile.runtimeVersion(), false, entries);
-    }
-
-    @Override
-    public Optional<ModuleReference> find(String name) {
-        Objects.requireNonNull(name);
-
-        // try cached modules
-        ModuleReference m = cachedModules.get(name);
-        if (m != null)
-            return Optional.of(m);
-
-        // the module may not have been encountered yet
-        while (hasNextEntry()) {
-            scanNextEntry();
-            m = cachedModules.get(name);
-            if (m != null)
-                return Optional.of(m);
-        }
-        return Optional.empty();
-    }
-
-    @Override
-    public Set<ModuleReference> findAll() {
-        // need to ensure that all entries have been scanned
-        while (hasNextEntry()) {
-            scanNextEntry();
-        }
-        return cachedModules.values().stream().collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns {@code true} if there are additional entries to scan
-     */
-    private boolean hasNextEntry() {
-        return next < entries.length;
-    }
-
-    /**
-     * Scans the next entry on the module path. A no-op if all entries have
-     * already been scanned.
-     *
-     * @throws FindException if an error occurs scanning the next entry
-     */
-    private void scanNextEntry() {
-        if (hasNextEntry()) {
-
-            long t0 = System.nanoTime();
-
-            Path entry = entries[next];
-            Map<String, ModuleReference> modules = scan(entry);
-            next++;
-
-            // update cache, ignoring duplicates
-            int initialSize = cachedModules.size();
-            for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
-                cachedModules.putIfAbsent(e.getKey(), e.getValue());
-            }
-
-            // update counters
-            int added = cachedModules.size() - initialSize;
-            moduleCount.add(added);
-
-            scanTime.addElapsedTimeFrom(t0);
-        }
-    }
-
-
-    /**
-     * Scan the given module path entry. If the entry is a directory then it is
-     * a directory of modules or an exploded module. If the entry is a regular
-     * file then it is assumed to be a packaged module.
-     *
-     * @throws FindException if an error occurs scanning the entry
-     */
-    private Map<String, ModuleReference> scan(Path entry) {
-
-        BasicFileAttributes attrs;
-        try {
-            attrs = Files.readAttributes(entry, BasicFileAttributes.class);
-        } catch (NoSuchFileException e) {
-            return Collections.emptyMap();
-        } catch (IOException ioe) {
-            throw new FindException(ioe);
-        }
-
-        try {
-
-            if (attrs.isDirectory()) {
-                Path mi = entry.resolve(MODULE_INFO);
-                if (!Files.exists(mi)) {
-                    // does not exist or unable to determine so assume a
-                    // directory of modules
-                    return scanDirectory(entry);
-                }
-            }
-
-            // packaged or exploded module
-            ModuleReference mref = readModule(entry, attrs);
-            if (mref != null) {
-                String name = mref.descriptor().name();
-                return Collections.singletonMap(name, mref);
-            } else {
-                // skipped
-                return Collections.emptyMap();
-            }
-
-        } catch (IOException ioe) {
-            throw new FindException(ioe);
-        }
-    }
-
-
-    /**
-     * Scans the given directory for packaged or exploded modules.
-     *
-     * @return a map of module name to ModuleReference for the modules found
-     *         in the directory
-     *
-     * @throws IOException if an I/O error occurs
-     * @throws FindException if an error occurs scanning the entry or the
-     *         directory contains two or more modules with the same name
-     */
-    private Map<String, ModuleReference> scanDirectory(Path dir)
-        throws IOException
-    {
-        // The map of name -> mref of modules found in this directory.
-        Map<String, ModuleReference> nameToReference = new HashMap<>();
-
-        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
-            for (Path entry : stream) {
-                BasicFileAttributes attrs;
-                try {
-                    attrs = Files.readAttributes(entry, BasicFileAttributes.class);
-                } catch (NoSuchFileException ignore) {
-                    // file has been removed or moved, ignore for now
-                    continue;
-                }
-
-                ModuleReference mref = readModule(entry, attrs);
-
-                // module found
-                if (mref != null) {
-                    // can have at most one version of a module in the directory
-                    String name = mref.descriptor().name();
-                    ModuleReference previous = nameToReference.put(name, mref);
-                    if (previous != null) {
-                        String fn1 = fileName(mref);
-                        String fn2 = fileName(previous);
-                        throw new FindException("Two versions of module "
-                                                 + name + " found in " + dir
-                                                 + " (" + fn1 + " and " + fn2 + ")");
-                    }
-                }
-            }
-        }
-
-        return nameToReference;
-    }
-
-
-    /**
-     * Locates a packaged or exploded module, returning a {@code ModuleReference}
-     * to the module. Returns {@code null} if the entry is skipped because it is
-     * to a directory that does not contain a module-info.class or it's a hidden
-     * file.
-     *
-     * @throws IOException if an I/O error occurs
-     * @throws FindException if the file is not recognized as a module or an
-     *         error occurs parsing its module descriptor
-     */
-    private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
-        throws IOException
-    {
-        try {
-
-            if (attrs.isDirectory()) {
-                return readExplodedModule(entry); // may return null
-            }
-
-            String fn = entry.getFileName().toString();
-            if (attrs.isRegularFile()) {
-                if (fn.endsWith(".jar")) {
-                    return readJar(entry);
-                } else if (fn.endsWith(".jmod")) {
-                    if (isLinkPhase)
-                        return readJMod(entry);
-                    throw new FindException("JMOD files not supported: " + entry);
-                }
-            }
-
-            // skip hidden files
-            if (fn.startsWith(".") || Files.isHidden(entry)) {
-                return null;
-            } else {
-                throw new FindException("Unrecognized module: " + entry);
-            }
-
-        } catch (InvalidModuleDescriptorException e) {
-            throw new FindException("Error reading module: " + entry, e);
-        }
-    }
-
-
-    /**
-     * Returns a string with the file name of the module if possible.
-     * If the module location is not a file URI then return the URI
-     * as a string.
-     */
-    private String fileName(ModuleReference mref) {
-        URI uri = mref.location().orElse(null);
-        if (uri != null) {
-            if (uri.getScheme().equalsIgnoreCase("file")) {
-                Path file = Paths.get(uri);
-                return file.getFileName().toString();
-            } else {
-                return uri.toString();
-            }
-        } else {
-            return "<unknown>";
-        }
-    }
-
-    // -- jmod files --
-
-    private Set<String> jmodPackages(JmodFile jf) {
-        return jf.stream()
-            .filter(e -> e.section() == Section.CLASSES)
-            .map(JmodFile.Entry::name)
-            .map(this::toPackageName)
-            .flatMap(Optional::stream)
-            .collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to a module in jmod file on the
-     * file system.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readJMod(Path file) throws IOException {
-        try (JmodFile jf = new JmodFile(file)) {
-            ModuleDescriptor md;
-            try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
-                md = ModuleDescriptor.read(in, () -> jmodPackages(jf));
-            }
-            return ModuleReferences.newJModModule(md, file);
-        }
-    }
-
-
-    // -- JAR files --
-
-    private static final String SERVICES_PREFIX = "META-INF/services/";
-
-    /**
-     * Returns the service type corresponding to the name of a services
-     * configuration file if it is a valid Java identifier.
-     *
-     * For example, if called with "META-INF/services/p.S" then this method
-     * returns a container with the value "p.S".
-     */
-    private Optional<String> toServiceName(String cf) {
-        assert cf.startsWith(SERVICES_PREFIX);
-        int index = cf.lastIndexOf("/") + 1;
-        if (index < cf.length()) {
-            String prefix = cf.substring(0, index);
-            if (prefix.equals(SERVICES_PREFIX)) {
-                String sn = cf.substring(index);
-                if (Checks.isJavaIdentifier(sn))
-                    return Optional.of(sn);
-            }
-        }
-        return Optional.empty();
-    }
-
-    /**
-     * Reads the next line from the given reader and trims it of comments and
-     * leading/trailing white space.
-     *
-     * Returns null if the reader is at EOF.
-     */
-    private String nextLine(BufferedReader reader) throws IOException {
-        String ln = reader.readLine();
-        if (ln != null) {
-            int ci = ln.indexOf('#');
-            if (ci >= 0)
-                ln = ln.substring(0, ci);
-            ln = ln.trim();
-        }
-        return ln;
-    }
-
-    /**
-     * Treat the given JAR file as a module as follows:
-     *
-     * 1. The module name (and optionally the version) is derived from the file
-     *    name of the JAR file
-     * 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
-     *    is mapped to the module descriptor mainClass
-     */
-    private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
-        throws IOException
-    {
-        // Derive module name and version from JAR file name
-
-        String fn = jf.getName();
-        int i = fn.lastIndexOf(File.separator);
-        if (i != -1)
-            fn = fn.substring(i+1);
-
-        // drop .jar
-        String mn = fn.substring(0, fn.length()-4);
-        String vs = null;
-
-        // find first occurrence of -${NUMBER}. or -${NUMBER}$
-        Matcher matcher = Patterns.DASH_VERSION.matcher(mn);
-        if (matcher.find()) {
-            int start = matcher.start();
-
-            // attempt to parse the tail as a version string
-            try {
-                String tail = mn.substring(start+1);
-                ModuleDescriptor.Version.parse(tail);
-                vs = tail;
-            } catch (IllegalArgumentException ignore) { }
-
-            mn = mn.substring(0, start);
-        }
-
-        // finally clean up the module name
-        mn = cleanModuleName(mn);
-
-        // Builder throws IAE if module name is empty or invalid
-        ModuleDescriptor.Builder builder
-            = ModuleDescriptor.automaticModule(mn)
-                .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
-        if (vs != null)
-            builder.version(vs);
-
-        // scan the names of the entries in the JAR file
-        Map<Boolean, Set<String>> map = VersionedStream.stream(jf)
-                .filter(e -> !e.isDirectory())
-                .map(JarEntry::getName)
-                .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
-                                                   Collectors.toSet()));
-
-        Set<String> resources = map.get(Boolean.FALSE);
-        Set<String> configFiles = map.get(Boolean.TRUE);
-        // all packages are exported and open
-        resources.stream()
-                .map(this::toPackageName)
-                .flatMap(Optional::stream)
-                .distinct()
-                .forEach(pn -> builder.exports(pn).opens(pn));
-
-        // map names of service configuration files to service names
-        Set<String> serviceNames = configFiles.stream()
-                .map(this::toServiceName)
-                .flatMap(Optional::stream)
-                .collect(Collectors.toSet());
-
-        // parse each service configuration file
-        for (String sn : serviceNames) {
-            JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
-            List<String> providerClasses = new ArrayList<>();
-            try (InputStream in = jf.getInputStream(entry)) {
-                BufferedReader reader
-                    = new BufferedReader(new InputStreamReader(in, "UTF-8"));
-                String cn;
-                while ((cn = nextLine(reader)) != null) {
-                    if (cn.length() > 0) {
-                        providerClasses.add(cn);
-                    }
-                }
-            }
-            if (!providerClasses.isEmpty())
-                builder.provides(sn, providerClasses);
-        }
-
-        // Main-Class attribute if it exists
-        Manifest man = jf.getManifest();
-        if (man != null) {
-            Attributes attrs = man.getMainAttributes();
-            String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
-            if (mainClass != null)
-                builder.mainClass(mainClass.replace("/", "."));
-        }
-
-        return builder.build();
-    }
-
-    /**
-     * Patterns used to derive the module name from a JAR file name.
-     */
-    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("^\\.");
-        static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
-    }
-
-    /**
-     * 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(".");
-
-        // collapse repeating dots
-        mn = Patterns.REPEATING_DOTS.matcher(mn).replaceAll(".");
-
-        // drop leading dots
-        if (mn.length() > 0 && mn.charAt(0) == '.')
-            mn = Patterns.LEADING_DOTS.matcher(mn).replaceAll("");
-
-        // drop trailing dots
-        int len = mn.length();
-        if (len > 0 && mn.charAt(len-1) == '.')
-            mn = Patterns.TRAILING_DOTS.matcher(mn).replaceAll("");
-
-        return mn;
-    }
-
-    private Set<String> jarPackages(JarFile jf) {
-        return VersionedStream.stream(jf)
-                .filter(e -> !e.isDirectory())
-                .map(JarEntry::getName)
-                .map(this::toPackageName)
-                .flatMap(Optional::stream)
-                .collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to a module in modular JAR file on
-     * the file system.
-     *
-     * @throws IOException
-     * @throws FindException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readJar(Path file) throws IOException {
-        try (JarFile jf = new JarFile(file.toFile(),
-                                      true,               // verify
-                                      ZipFile.OPEN_READ,
-                                      releaseVersion))
-        {
-            ModuleDescriptor md;
-            JarEntry entry = jf.getJarEntry(MODULE_INFO);
-            if (entry == null) {
-
-                // no module-info.class so treat it as automatic module
-                try {
-                    md = deriveModuleDescriptor(jf);
-                } catch (IllegalArgumentException iae) {
-                    throw new FindException(
-                        "Unable to derive module descriptor for: "
-                        + jf.getName(), iae);
-                }
-
-            } else {
-                md = ModuleDescriptor.read(jf.getInputStream(entry),
-                                           () -> jarPackages(jf));
-            }
-
-            return ModuleReferences.newJarModule(md, file);
-        }
-    }
-
-
-    // -- exploded directories --
-
-    private Set<String> explodedPackages(Path dir) {
-        try {
-            return Files.find(dir, Integer.MAX_VALUE,
-                              ((path, attrs) -> attrs.isRegularFile()))
-                    .map(path -> dir.relativize(path))
-                    .map(this::toPackageName)
-                    .flatMap(Optional::stream)
-                    .collect(Collectors.toSet());
-        } catch (IOException x) {
-            throw new UncheckedIOException(x);
-        }
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to an exploded module on the file
-     * system or {@code null} if {@code module-info.class} not found.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readExplodedModule(Path dir) throws IOException {
-        Path mi = dir.resolve(MODULE_INFO);
-        ModuleDescriptor md;
-        try (InputStream in = Files.newInputStream(mi)) {
-            md = ModuleDescriptor.read(new BufferedInputStream(in),
-                                       () -> explodedPackages(dir));
-        } catch (NoSuchFileException e) {
-            // for now
-            return null;
-        }
-        return ModuleReferences.newExplodedModule(md, dir);
-    }
-
-    /**
-     * Maps the name of an entry in a JAR or ZIP file to a package name.
-     *
-     * @throws IllegalArgumentException if the name is a class file in
-     *         the top-level directory of the JAR/ZIP file (and it's
-     *         not module-info.class)
-     */
-    private Optional<String> toPackageName(String name) {
-        assert !name.endsWith("/");
-
-        int index = name.lastIndexOf("/");
-        if (index == -1) {
-            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
-                throw new IllegalArgumentException(name
-                        + " found in top-level directory:"
-                        + " (unnamed package not allowed in module)");
-            }
-            return Optional.empty();
-        }
-
-        String pn = name.substring(0, index).replace('/', '.');
-        if (Checks.isJavaIdentifier(pn)) {
-            return Optional.of(pn);
-        } else {
-            // not a valid package name
-            return Optional.empty();
-        }
-    }
-
-    /**
-     * Maps the relative path of an entry in an exploded module to a package
-     * name.
-     *
-     * @throws IllegalArgumentException if the name is a class file in
-     *         the top-level directory (and it's not module-info.class)
-     */
-    private Optional<String> toPackageName(Path file) {
-        assert file.getRoot() == null;
-
-        Path parent = file.getParent();
-        if (parent == null) {
-            String name = file.toString();
-            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
-                throw new IllegalArgumentException(name
-                        + " found in in top-level directory"
-                        + " (unnamed package not allowed in module)");
-            }
-            return Optional.empty();
-        }
-
-        String pn = parent.toString().replace(File.separatorChar, '.');
-        if (Checks.isJavaIdentifier(pn)) {
-            return Optional.of(pn);
-        } else {
-            // not a valid package name
-            return Optional.empty();
-        }
-    }
-
-    private static final PerfCounter scanTime
-        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
-    private static final PerfCounter moduleCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Mon Dec 19 09:16:40 2016 -0800
@@ -26,96 +26,42 @@
 package java.lang.module;
 
 import java.io.IOException;
-import java.io.UncheckedIOException;
 import java.net.URI;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes.HashSupplier;
 
 
 /**
  * A reference to a module's content.
  *
- * <p> A module reference contains the module's descriptor and its location, if
- * known.  It also has the ability to create a {@link ModuleReader} in order to
- * access the module's content, which may be inside the Java run-time system
- * itself or in an artifact such as a modular JAR file.
+ * <p> A module reference is a concrete implementation of this class that
+ * implements the abstract methods defined by this class. It contains the
+ * module's descriptor and its location, if known.  It also has the ability to
+ * create a {@link ModuleReader} in order to access the module's content, which
+ * may be inside the Java run-time system itself or in an artifact such as a
+ * modular JAR file.
  *
  * @see ModuleFinder
  * @see ModuleReader
  * @since 9
  */
 
-public final class ModuleReference {
+public abstract class ModuleReference {
 
     private final ModuleDescriptor descriptor;
     private final URI location;
-    private final Supplier<ModuleReader> readerSupplier;
-
-    // true if this is a reference to a patched module
-    private boolean patched;
-
-    // the function that computes the hash of this module reference
-    private final HashSupplier hasher;
-
-    // cached hash to avoid needing to compute it many times
-    private byte[] cachedHash;
-
 
     /**
      * Constructs a new instance of this class.
-     */
-    ModuleReference(ModuleDescriptor descriptor,
-                    URI location,
-                    Supplier<ModuleReader> readerSupplier,
-                    boolean patched,
-                    HashSupplier hasher)
-
-    {
-        this.descriptor = Objects.requireNonNull(descriptor);
-        this.location = location;
-        this.readerSupplier = Objects.requireNonNull(readerSupplier);
-        this.patched = patched;
-        this.hasher = hasher;
-    }
-
-    /**
-     * Constructs a new instance of this class.
-     */
-    ModuleReference(ModuleDescriptor descriptor,
-                    URI location,
-                    Supplier<ModuleReader> readerSupplier,
-                    HashSupplier hasher)
-
-    {
-        this(descriptor, location, readerSupplier, false, hasher);
-    }
-
-
-    /**
-     * Constructs a new instance of this class.
-     *
-     * <p> The {@code readSupplier} parameter is the supplier of the {@link
-     * ModuleReader} that may be used to read the module content. Its {@link
-     * Supplier#get() get()} method throws {@link UncheckedIOException} if an
-     * I/O error occurs opening the module content. The {@code get()} method
-     * throws {@link SecurityException} if opening the module is denied by the
-     * security manager.
      *
      * @param descriptor
      *        The module descriptor
      * @param location
      *        The module location or {@code null} if not known
-     * @param readerSupplier
-     *        The {@code Supplier} of the {@code ModuleReader}
      */
-    public ModuleReference(ModuleDescriptor descriptor,
-                           URI location,
-                           Supplier<ModuleReader> readerSupplier)
-    {
-        this(descriptor, location, readerSupplier, false, null);
+    protected ModuleReference(ModuleDescriptor descriptor, URI location) {
+        this.descriptor = Objects.requireNonNull(descriptor);
+        this.location = location;
     }
 
     /**
@@ -123,11 +69,10 @@
      *
      * @return The module descriptor
      */
-    public ModuleDescriptor descriptor() {
+    public final ModuleDescriptor descriptor() {
         return descriptor;
     }
 
-
     /**
      * Returns the location of this module's content, if known.
      *
@@ -139,18 +84,13 @@
      *
      * @return The location or an empty {@code Optional} if not known
      */
-    public Optional<URI> location() {
+    public final Optional<URI> location() {
         return Optional.ofNullable(location);
     }
 
-
     /**
      * Opens the module content for reading.
      *
-     * <p> This method opens the module content by invoking the {@link
-     * Supplier#get() get()} method of the {@code readSupplier} specified at
-     * construction time. </p>
-     *
      * @return A {@code ModuleReader} to read the module
      *
      * @throws IOException
@@ -158,113 +98,5 @@
      * @throws SecurityException
      *         If denied by the security manager
      */
-    public ModuleReader open() throws IOException {
-        try {
-            return readerSupplier.get();
-        } catch (UncheckedIOException e) {
-            throw e.getCause();
-        }
-
-    }
-
-
-    /**
-     * Returns {@code true} if this module has been patched via --patch-module.
-     */
-    boolean isPatched() {
-        return patched;
-    }
-
-    /**
-     * Returns the hash supplier for this module.
-     */
-    HashSupplier hasher() {
-        return hasher;
-    }
-
-    /**
-     * 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
-     */
-    byte[] computeHash(String algorithm) {
-        byte[] result = cachedHash;
-        if (result != null)
-            return result;
-        if (hasher == null)
-            return null;
-        cachedHash = result = hasher.generate(algorithm);
-        return result;
-    }
-
-    /**
-     * Computes a hash code for this module reference.
-     *
-     * <p> The hash code is based upon the components of the reference, and
-     * satisfies the general contract of the {@link Object#hashCode
-     * Object.hashCode} method. </p>
-     *
-     * @return The hash-code value for this module reference
-     */
-    @Override
-    public int hashCode() {
-        int hc = hash;
-        if (hc == 0) {
-            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;
-        }
-        return hc;
-    }
-
-    private int hash;
-
-    /**
-     * Tests this module reference for equality with the given object.
-     *
-     * <p> If the given object is not a {@code ModuleReference} then this
-     * method returns {@code false}. Two module references are equal if their
-     * module descriptors are equal, their locations are equal or both unknown,
-     * and were created with equal supplier objects to access the module
-     * content. </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
-     *          reference that is equal to this module reference
-     */
-    @Override
-    public boolean equals(Object ob) {
-        if (!(ob instanceof ModuleReference))
-            return false;
-        ModuleReference that = (ModuleReference)ob;
-
-        return Objects.equals(this.descriptor, that.descriptor)
-                && Objects.equals(this.location, that.location)
-                && Objects.equals(this.readerSupplier, that.readerSupplier)
-                && Objects.equals(this.hasher, that.hasher)
-                && this.patched == that.patched;
-    }
-
-    /**
-     * Returns a string describing this module reference.
-     *
-     * @return A string describing this module reference
-     */
-    @Override
-    public String toString() {
-        return ("[module " + descriptor().name()
-                + ", location=" + location + "]");
-    }
-
+    public abstract ModuleReader open() throws IOException;
 }
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,443 +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 java.lang.module;
-
-import java.io.File;
-import java.io.IOError;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.function.Supplier;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.ZipFile;
-
-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;
-import jdk.internal.util.jar.VersionedStream;
-import sun.net.www.ParseUtil;
-
-
-/**
- * A factory for creating ModuleReference implementations where the modules are
- * packaged as modular JAR file, JMOD files or where the modules are exploded
- * on the file system.
- */
-
-class ModuleReferences {
-
-    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
-
-    private ModuleReferences() { }
-
-    /**
-     * Creates a ModuleReference to a module or to patched module when
-     * creating modules for the boot Layer and --patch-module is specified.
-     */
-    private static ModuleReference newModule(ModuleDescriptor md,
-                                             URI uri,
-                                             Supplier<ModuleReader> supplier,
-                                             HashSupplier hasher) {
-
-        ModuleReference mref = new ModuleReference(md, uri, supplier, hasher);
-        if (JLA.getBootLayer() == null)
-            mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
-        return mref;
-    }
-
-    /**
-     * Creates a ModuleReference to a module packaged as a modular JAR.
-     */
-    static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
-        URI uri = file.toUri();
-        Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
-        return newModule(md, uri, supplier, hasher);
-    }
-
-    /**
-     * Creates a ModuleReference to a module packaged as a JMOD.
-     */
-    static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
-        URI uri = file.toUri();
-        Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
-        return newModule(md, file.toUri(), supplier, hasher);
-    }
-
-    /**
-     * Creates a ModuleReference to an exploded module.
-     */
-    static ModuleReference newExplodedModule(ModuleDescriptor md, Path dir) {
-        Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
-        return newModule(md, dir.toUri(), supplier, null);
-    }
-
-
-    /**
-     * A base module reader that encapsulates machinery required to close the
-     * module reader safely.
-     */
-    static abstract class SafeCloseModuleReader implements ModuleReader {
-
-        // RW lock to support safe close
-        private final ReadWriteLock lock = new ReentrantReadWriteLock();
-        private final Lock readLock = lock.readLock();
-        private final Lock writeLock = lock.writeLock();
-        private boolean closed;
-
-        SafeCloseModuleReader() { }
-
-        /**
-         * Returns a URL to  resource. This method is invoked by the find
-         * method to do the actual work of finding the resource.
-         */
-        abstract Optional<URI> implFind(String name) throws IOException;
-
-        /**
-         * Returns an input stream for reading a resource. This method is
-         * invoked by the open method to do the actual work of opening
-         * an input stream to the resource.
-         */
-        abstract Optional<InputStream> implOpen(String name) throws IOException;
-
-        /**
-         * Returns a stream of the names of resources in the module. This
-         * method is invoked by the list method to do the actual work of
-         * creating the stream.
-         */
-        abstract Stream<String> implList() throws IOException;
-
-        /**
-         * Closes the module reader. This method is invoked by close to do the
-         * actual work of closing the module reader.
-         */
-        abstract void implClose() throws IOException;
-
-        @Override
-        public final Optional<URI> find(String name) throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implFind(name);
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-
-        @Override
-        public final Optional<InputStream> open(String name) throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implOpen(name);
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        @Override
-        public final Stream<String> list() throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implList();
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        @Override
-        public final void close() throws IOException {
-            writeLock.lock();
-            try {
-                if (!closed) {
-                    closed = true;
-                    implClose();
-                }
-            } finally {
-                writeLock.unlock();
-            }
-        }
-    }
-
-
-    /**
-     * A ModuleReader for a modular JAR file.
-     */
-    static class JarModuleReader extends SafeCloseModuleReader {
-        private final JarFile jf;
-        private final URI uri;
-
-        static JarFile newJarFile(Path path) {
-            try {
-                return new JarFile(path.toFile(),
-                                   true,               // verify
-                                   ZipFile.OPEN_READ,
-                                   JarFile.runtimeVersion());
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-        }
-
-        JarModuleReader(Path path, URI uri) {
-            this.jf = newJarFile(path);
-            this.uri = uri;
-        }
-
-        private JarEntry getEntry(String name) {
-            return jf.getJarEntry(Objects.requireNonNull(name));
-        }
-
-        @Override
-        Optional<URI> implFind(String name) throws IOException {
-            JarEntry je = getEntry(name);
-            if (je != null) {
-                if (jf.isMultiRelease())
-                    name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
-                String encodedPath = ParseUtil.encodePath(name, false);
-                String uris = "jar:" + uri + "!/" + encodedPath;
-                return Optional.of(URI.create(uris));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Optional<InputStream> implOpen(String name) throws IOException {
-            JarEntry je = getEntry(name);
-            if (je != null) {
-                return Optional.of(jf.getInputStream(je));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Stream<String> implList() throws IOException {
-            // take snapshot to avoid async close
-            List<String> names = VersionedStream.stream(jf)
-                    .filter(e -> !e.isDirectory())
-                    .map(JarEntry::getName)
-                    .collect(Collectors.toList());
-            return names.stream();
-        }
-
-        @Override
-        void implClose() throws IOException {
-            jf.close();
-        }
-    }
-
-
-    /**
-     * A ModuleReader for a JMOD file.
-     */
-    static class JModModuleReader extends SafeCloseModuleReader {
-        private final JmodFile jf;
-        private final URI uri;
-
-        static JmodFile newJmodFile(Path path) {
-            try {
-                return new JmodFile(path);
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-        }
-
-        JModModuleReader(Path path, URI uri) {
-            this.jf = newJmodFile(path);
-            this.uri = uri;
-        }
-
-        private JmodFile.Entry getEntry(String name) {
-            Objects.requireNonNull(name);
-            return jf.getEntry(JmodFile.Section.CLASSES, name);
-        }
-
-        @Override
-        Optional<URI> implFind(String name) {
-            JmodFile.Entry je = getEntry(name);
-            if (je != null) {
-                String encodedPath = ParseUtil.encodePath(name, false);
-                String uris = "jmod:" + uri + "!/" + encodedPath;
-                return Optional.of(URI.create(uris));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Optional<InputStream> implOpen(String name) throws IOException {
-            JmodFile.Entry je = getEntry(name);
-            if (je != null) {
-                return Optional.of(jf.getInputStream(je));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Stream<String> implList() throws IOException {
-            // take snapshot to avoid async close
-            List<String> names = jf.stream()
-                    .filter(e -> e.section() == JmodFile.Section.CLASSES)
-                    .map(JmodFile.Entry::name)
-                    .collect(Collectors.toList());
-            return names.stream();
-        }
-
-        @Override
-        void implClose() throws IOException {
-            jf.close();
-        }
-    }
-
-
-    /**
-     * A ModuleReader for an exploded module.
-     */
-    static class ExplodedModuleReader implements ModuleReader {
-        private final Path dir;
-        private volatile boolean closed;
-
-        ExplodedModuleReader(Path dir) {
-            this.dir = dir;
-
-            // when running with a security manager then check that the caller
-            // has access to the directory.
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                boolean unused = Files.isDirectory(dir);
-            }
-        }
-
-        /**
-         * Returns a Path to access to the given resource.
-         */
-        private Path toPath(String name) {
-            Path path = Paths.get(name.replace('/', File.separatorChar));
-            if (path.getRoot() == null) {
-                return dir.resolve(path);
-            } else {
-                // drop the root component so that the resource is
-                // located relative to the module directory
-                int n = path.getNameCount();
-                return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
-            }
-        }
-
-        /**
-         * Throws IOException if the module reader is closed;
-         */
-        private void ensureOpen() throws IOException {
-            if (closed) throw new IOException("ModuleReader is closed");
-        }
-
-        @Override
-        public Optional<URI> find(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                try {
-                    return Optional.of(path.toUri());
-                } catch (IOError e) {
-                    throw (IOException) e.getCause();
-                }
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<InputStream> open(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                return Optional.of(Files.newInputStream(path));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<ByteBuffer> read(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Stream<String> list() throws IOException {
-            ensureOpen();
-            // sym links not followed
-            return Files.find(dir, Integer.MAX_VALUE,
-                              (path, attrs) -> attrs.isRegularFile())
-                    .map(f -> dir.relativize(f)
-                                 .toString()
-                                 .replace(File.separatorChar, '/'));
-        }
-
-        @Override
-        public void close() {
-            closed = true;
-        }
-    }
-
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Mon Dec 19 09:16:40 2016 -0800
@@ -46,6 +46,7 @@
 import java.util.stream.Collectors;
 
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
 
 /**
  * The resolver used by {@link Configuration#resolveRequires} and
@@ -438,24 +439,32 @@
      */
     private void checkHashes() {
         for (ModuleReference mref : nameToReference.values()) {
+
+            // get the recorded hashes, if any
+            if (!(mref instanceof ModuleReferenceImpl))
+                continue;
+            ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
+            if (hashes == null)
+                continue;
+
             ModuleDescriptor descriptor = mref.descriptor();
-
-            // get map of module hashes
-            Optional<ModuleHashes> ohashes = descriptor.hashes();
-            if (!ohashes.isPresent())
-                continue;
-            ModuleHashes hashes = ohashes.get();
-
             String algorithm = hashes.algorithm();
             for (String dn : hashes.names()) {
-                ModuleReference other = nameToReference.get(dn);
-                if (other == null) {
+                ModuleReference mref2 = nameToReference.get(dn);
+                if (mref2 == null) {
                     ResolvedModule resolvedModule = findInParent(dn);
                     if (resolvedModule != null)
-                        other = resolvedModule.reference();
+                        mref2 = resolvedModule.reference();
+                }
+                if (mref2 == null)
+                    continue;
+
+                if (!(mref2 instanceof ModuleReferenceImpl)) {
+                    fail("Unable to compute the hash of module %s", dn);
                 }
 
                 // skip checking the hash if the module has been patched
+                ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
                 if (other != null && !other.isPatched()) {
                     byte[] recordedHash = hashes.hashFor(dn);
                     byte[] actualHash = other.computeHash(algorithm);
--- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,443 +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 java.lang.module;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.net.URLConnection;
-import java.nio.ByteBuffer;
-import java.util.ArrayDeque;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-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;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.ImageReader;
-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;
-import jdk.internal.module.ModulePatcher;
-import jdk.internal.perf.PerfCounter;
-
-/**
- * A {@code ModuleFinder} that finds modules that are linked into the
- * run-time image.
- *
- * The modules linked into the run-time image are assumed to have the
- * Packages attribute.
- */
-
-class SystemModuleFinder implements ModuleFinder {
-
-    private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
-
-    private static final PerfCounter initTime
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
-    private static final PerfCounter moduleCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
-    private static final PerfCounter packageCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
-    private static final PerfCounter exportsCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
-    // ImageReader used to access all modules in the image
-    private static final ImageReader imageReader;
-
-    // the set of modules in the run-time image
-    private static final Set<ModuleReference> modules;
-
-    // maps module name to module reference
-    private static final Map<String, ModuleReference> nameToModule;
-
-    /**
-     * For now, the module references are created eagerly on the assumption
-     * that service binding will require all modules to be located.
-     */
-    static {
-        long t0 = System.nanoTime();
-        imageReader = ImageReaderFactory.getImageReader();
-
-        String[] names = moduleNames();
-        ModuleDescriptor[] descriptors = descriptors(names);
-
-        int n = names.length;
-        moduleCount.add(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];
-
-            // create the ModuleReference
-            ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i]));
-
-            mods[i] = mref;
-            map[i] = Map.entry(names[i], mref);
-
-            // counters
-            packageCount.add(md.packages().size());
-            exportsCount.add(md.exports().size());
-        }
-
-        modules = Set.of(mods);
-        nameToModule = Map.ofEntries(map);
-
-        initTime.addElapsedTimeFrom(t0);
-    }
-
-    /*
-     * Returns an array of ModuleDescriptor of the given module names.
-     *
-     * This obtains ModuleDescriptors from SystemModules class that is generated
-     * from the jlink system-modules plugin.  ModuleDescriptors have already
-     * been validated at link time.
-     *
-     * If java.base is patched, or fastpath is disabled for troubleshooting
-     * purpose, it will fall back to find system modules via jrt file system.
-     */
-    private static ModuleDescriptor[] descriptors(String[] names) {
-        // fastpath is enabled by default.
-        // It can be disabled for troubleshooting purpose.
-        boolean disabled =
-            System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
-
-        // fast loading of ModuleDescriptor of system modules
-        if (isFastPathSupported() && !disabled)
-            return SystemModules.modules();
-
-        // if fast loading of ModuleDescriptors is disabled
-        // fallback to read module-info.class
-        ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length];
-        for (int i = 0; i < names.length; i++) {
-            String mn = names[i];
-            ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
-            descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc));
-
-            // add the recorded hashes of tied modules
-            Hashes.add(descriptors[i]);
-        }
-        return descriptors;
-    }
-
-    private static boolean isFastPathSupported() {
-       return SystemModules.MODULE_NAMES.length > 0;
-    }
-
-    private static String[] moduleNames() {
-        if (isFastPathSupported())
-            // module names recorded at link time
-            return SystemModules.MODULE_NAMES;
-
-        // this happens when java.base is patched with java.base
-        // from an exploded image
-        return imageReader.getModuleNames();
-    }
-
-    private static ModuleReference toModuleReference(ModuleDescriptor md,
-                                                     HashSupplier hash)
-    {
-        String mn = md.name();
-        URI uri = JNUA.create("jrt", "/".concat(mn));
-
-        Supplier<ModuleReader> readerSupplier = new Supplier<>() {
-            @Override
-            public ModuleReader get() {
-                return new ImageModuleReader(mn, uri);
-            }
-        };
-
-        ModuleReference mref =
-            new ModuleReference(md, uri, readerSupplier, hash);
-
-        // may need a reference to a patched module if --patch-module specified
-        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
-        return mref;
-    }
-
-    private static HashSupplier hashSupplier(int index, String name) {
-        if (isFastPathSupported()) {
-            return new HashSupplier() {
-                @Override
-                public byte[] generate(String algorithm) {
-                    return SystemModules.MODULES_TO_HASH[index];
-                }
-            };
-        } else {
-            return Hashes.hashFor(name);
-        }
-    }
-
-    /*
-     * This helper class is only used when SystemModules is patched.
-     * It will get the recorded hashes from module-info.class.
-     */
-    private static class Hashes {
-        static Map<String, byte[]> hashes = new HashMap<>();
-
-        static void add(ModuleDescriptor descriptor) {
-            Optional<ModuleHashes> ohashes = descriptor.hashes();
-            if (ohashes.isPresent()) {
-                hashes.putAll(ohashes.get().hashes());
-            }
-        }
-
-        static HashSupplier hashFor(String name) {
-            if (!hashes.containsKey(name))
-                return null;
-
-            return new HashSupplier() {
-                @Override
-                public byte[] generate(String algorithm) {
-                    return hashes.get(name);
-                }
-            };
-        }
-    }
-
-    SystemModuleFinder() { }
-
-    @Override
-    public Optional<ModuleReference> find(String name) {
-        Objects.requireNonNull(name);
-        return Optional.ofNullable(nameToModule.get(name));
-    }
-
-    @Override
-    public Set<ModuleReference> findAll() {
-        return modules;
-    }
-
-
-    /**
-     * A ModuleReader for reading resources from a module linked into the
-     * run-time image.
-     */
-    static class ImageModuleReader implements ModuleReader {
-        private final String module;
-        private volatile boolean closed;
-
-        /**
-         * If there is a security manager set then check permission to
-         * connect to the run-time image.
-         */
-        private static void checkPermissionToConnect(URI uri) {
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                try {
-                    URLConnection uc = uri.toURL().openConnection();
-                    sm.checkPermission(uc.getPermission());
-                } catch (IOException ioe) {
-                    throw new UncheckedIOException(ioe);
-                }
-            }
-        }
-
-        ImageModuleReader(String module, URI uri) {
-            checkPermissionToConnect(uri);
-            this.module = module;
-        }
-
-        /**
-         * Returns the ImageLocation for the given resource, {@code null}
-         * if not found.
-         */
-        private ImageLocation findImageLocation(String name) throws IOException {
-            Objects.requireNonNull(name);
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-            if (imageReader != null) {
-                return imageReader.findLocation(module, name);
-            } else {
-                // not an images build
-                return null;
-            }
-        }
-
-        @Override
-        public Optional<URI> find(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                URI u = URI.create("jrt:/" + module + "/" + name);
-                return Optional.of(u);
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<InputStream> open(String name) throws IOException {
-            return read(name).map(this::toInputStream);
-        }
-
-        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
-            try {
-                int rem = bb.remaining();
-                byte[] bytes = new byte[rem];
-                bb.get(bytes);
-                return new ByteArrayInputStream(bytes);
-            } finally {
-                release(bb);
-            }
-        }
-
-        @Override
-        public Optional<ByteBuffer> read(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                return Optional.of(imageReader.getResourceBuffer(location));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public void release(ByteBuffer bb) {
-            Objects.requireNonNull(bb);
-            ImageReader.releaseByteBuffer(bb);
-        }
-
-        @Override
-        public Stream<String> list() throws IOException {
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-
-            Spliterator<String> s = new ModuleContentSpliterator(module);
-            return StreamSupport.stream(s, false);
-        }
-
-        @Override
-        public void close() {
-            // nothing else to do
-            closed = true;
-        }
-    }
-
-    /**
-     * A Spliterator for traversing the resources of a module linked into the
-     * run-time image.
-     */
-    static class ModuleContentSpliterator implements Spliterator<String> {
-        final String moduleRoot;
-        final Deque<ImageReader.Node> stack;
-        Iterator<ImageReader.Node> iterator;
-
-        ModuleContentSpliterator(String module) throws IOException {
-            moduleRoot = "/modules/" + module;
-            stack = new ArrayDeque<>();
-
-            // push the root node to the stack to get started
-            ImageReader.Node dir = imageReader.findNode(moduleRoot);
-            if (dir == null || !dir.isDirectory())
-                throw new IOException(moduleRoot + " not a directory");
-            stack.push(dir);
-            iterator = Collections.emptyIterator();
-        }
-
-        /**
-         * Returns the name of the next non-directory node or {@code null} if
-         * there are no remaining nodes to visit.
-         */
-        private String next() throws IOException {
-            for (;;) {
-                while (iterator.hasNext()) {
-                    ImageReader.Node node = iterator.next();
-                    String name = node.getName();
-                    if (node.isDirectory()) {
-                        // build node
-                        ImageReader.Node dir = imageReader.findNode(name);
-                        assert dir.isDirectory();
-                        stack.push(dir);
-                    } else {
-                        // strip /modules/$MODULE/ prefix
-                        return name.substring(moduleRoot.length() + 1);
-                    }
-                }
-
-                if (stack.isEmpty()) {
-                    return null;
-                } else {
-                    ImageReader.Node dir = stack.poll();
-                    assert dir.isDirectory();
-                    iterator = dir.getChildren().iterator();
-                }
-            }
-        }
-
-        @Override
-        public boolean tryAdvance(Consumer<? super String> action) {
-            String next;
-            try {
-                next = next();
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-            if (next != null) {
-                action.accept(next);
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        @Override
-        public Spliterator<String> trySplit() {
-            return null;
-        }
-
-        @Override
-        public int characteristics() {
-            return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
-        }
-
-        @Override
-        public long estimateSize() {
-            return Long.MAX_VALUE;
-        }
-    }
-}
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Mon Dec 19 09:16:40 2016 -0800
@@ -28,9 +28,11 @@
 import java.lang.annotation.Annotation;
 import java.security.AccessController;
 
+import jdk.internal.misc.VM;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.reflect.ReflectionFactory;
+import sun.security.action.GetPropertyAction;
 
 /**
  * The AccessibleObject class is the base class for Field, Method and
@@ -172,8 +174,10 @@
 
         // package is open to caller
         String pn = packageName(declaringClass);
-        if (declaringModule.isOpen(pn, callerModule))
+        if (declaringModule.isOpen(pn, callerModule)) {
+            printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule);
             return;
+        }
 
         // package is exported to caller and class/member is public
         boolean isExported = declaringModule.isExported(pn, callerModule);
@@ -185,8 +189,10 @@
             modifiers = ((Field) this).getModifiers();
         }
         boolean isMemberPublic = Modifier.isPublic(modifiers);
-        if (isExported && isClassPublic && isMemberPublic)
+        if (isExported && isClassPublic && isMemberPublic) {
+            printStackTraceIfExportedReflectively(declaringModule, pn, callerModule);
             return;
+        }
 
         // not accessible
         String msg = "Unable to make ";
@@ -198,7 +204,44 @@
         else
             msg += "opens";
         msg += " " + pn + "\" to " + callerModule;
-        Reflection.throwInaccessibleObjectException(msg);
+        InaccessibleObjectException e = new InaccessibleObjectException(msg);
+        if (Reflection.printStackTraceWhenAccessFails()) {
+            e.printStackTrace(System.err);
+        }
+        throw e;
+    }
+
+    private void printStackTraceIfOpenedReflectively(Module module,
+                                                     String pn,
+                                                     Module other) {
+        printStackTraceIfExposedReflectively(module, pn, other, true);
+    }
+
+    private void printStackTraceIfExportedReflectively(Module module,
+                                                       String pn,
+                                                       Module other) {
+        printStackTraceIfExposedReflectively(module, pn, other, false);
+    }
+
+    private void printStackTraceIfExposedReflectively(Module module,
+                                                      String pn,
+                                                      Module other,
+                                                      boolean open)
+    {
+        if (Reflection.printStackTraceWhenAccessSucceeds()
+            && !module.isStaticallyExportedOrOpen(pn, other, open))
+        {
+            String msg = other + " allowed to invoke setAccessible on ";
+            if (this instanceof Field)
+                msg += "field ";
+            msg += this;
+            new Exception(msg) {
+                private static final long serialVersionUID = 42L;
+                public String toString() {
+                    return "WARNING: " + getMessage();
+                }
+            }.printStackTrace(System.err);
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Mon Dec 19 09:16:40 2016 -0800
@@ -246,7 +246,6 @@
          */
         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);
@@ -541,7 +540,7 @@
      * {@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
+     * ready to load from these modules before there are any attempts to load
      * classes or resources.
      *
      * <p> Creating a {@code Layer} can fail for the following reasons: </p>
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Mon Dec 19 09:16:40 2016 -0800
@@ -559,7 +559,7 @@
      * Returns {@code true} if this module exports or opens a package to
      * the given module via its module declaration.
      */
-    private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
+    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) {
@@ -643,6 +643,12 @@
      * <em>open</em>) to the given module. It also has no effect if
      * invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
      *
+     * @apiNote As specified in section 5.4.3 of the <cite>The Java&trade;
+     * Virtual Machine Specification </cite>, if an attempt to resolve a
+     * symbolic reference fails because of a linkage error, then subsequent
+     * attempts to resolve the reference always fail with the same error that
+     * was thrown as a result of the initial resolution attempt.
+     *
      * @param  pn
      *         The package name
      * @param  other
@@ -656,6 +662,7 @@
      * @throws IllegalStateException
      *         If this is a named module and the caller is not this module
      *
+     * @jvms 5.4.3 Resolution
      * @see #isExported(String,Module)
      */
     @CallerSensitive
@@ -676,8 +683,8 @@
     }
 
     /**
-     * If the caller's module is this module then update this module to
-     * <em>open</em> the given package to the given module.
+     * If this module has <em>opened</em> a package to at least the caller
+     * module then update this module to open the 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
@@ -699,7 +706,8 @@
      *         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
+     *         If this is a named module and this module has not opened the
+     *         package to at least the caller
      *
      * @see #isOpen(String,Module)
      * @see AccessibleObject#setAccessible(boolean)
@@ -713,9 +721,8 @@
 
         if (isNamed() && !descriptor.isOpen()) {
             Module caller = Reflection.getCallerClass().getModule();
-            if (caller != this) {
-                throw new IllegalStateException(caller + " != " + this);
-            }
+            if (caller != this && !isOpen(pn, caller))
+                throw new IllegalStateException(pn + " is not open to " + caller);
             implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
         }
 
@@ -1568,6 +1575,10 @@
                 public Stream<Layer> layers(ClassLoader loader) {
                     return Layer.layers(loader);
                 }
+                @Override
+                public boolean isStaticallyExported(Module module, String pn, Module other) {
+                    return module.isStaticallyExportedOrOpen(pn, other, false);
+                }
             });
     }
 }
--- a/jdk/src/java.base/share/classes/java/security/Signature.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/security/Signature.java	Mon Dec 19 09:16:40 2016 -0800
@@ -452,6 +452,10 @@
         return this.provider;
     }
 
+    private String getProviderName() {
+        return (provider == null)  ? "(no provider)" : provider.getName();
+    }
+
     void chooseFirstProvider() {
         // empty, overridden in Delegate
     }
@@ -473,7 +477,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " + this.provider.getName());
+                " verification algorithm from: " + getProviderName());
         }
     }
 
@@ -522,7 +526,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " verification algorithm from: " + this.provider.getName());
+                " verification algorithm from: " + getProviderName());
         }
     }
 
@@ -543,7 +547,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " + this.provider.getName());
+                " signing algorithm from: " + getProviderName());
         }
     }
 
@@ -566,7 +570,7 @@
 
         if (!skipDebug && pdebug != null) {
             pdebug.println("Signature." + algorithm +
-                " signing algorithm from: " + this.provider.getName());
+                " signing algorithm from: " + getProviderName());
         }
     }
 
--- a/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java	Mon Dec 19 09:16:40 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -73,11 +73,13 @@
 import java.io.Serializable;
 import java.time.DateTimeException;
 import java.time.LocalDate;
+import java.time.format.TextStyle;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalField;
 import java.time.temporal.UnsupportedTemporalTypeException;
 import java.time.temporal.ValueRange;
 import java.util.Arrays;
+import java.util.Locale;
 import java.util.Objects;
 
 import sun.util.calendar.CalendarDate;
@@ -125,8 +127,8 @@
      */
     public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
 
-    // the number of defined JapaneseEra constants.
-    // There could be an extra era defined in its configuration.
+    // The number of predefined JapaneseEra constants.
+    // There may be a supplemental era defined by the property.
     private static final int N_ERA_CONSTANTS = HEISEI.getValue() + ERA_OFFSET;
 
     /**
@@ -237,6 +239,32 @@
         return Arrays.copyOf(KNOWN_ERAS, KNOWN_ERAS.length);
     }
 
+    /**
+     * Gets the textual representation of this era.
+     * <p>
+     * This returns the textual name used to identify the era,
+     * suitable for presentation to the user.
+     * The parameters control the style of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getValue() numeric value}
+     * is returned.
+     *
+     * @param style  the style of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the era, not null
+     * @since 9
+     */
+    @Override
+    public String getDisplayName(TextStyle style, Locale locale) {
+        // If this JapaneseEra is a supplemental one, obtain the name from
+        // the era definition.
+        if (getValue() > N_ERA_CONSTANTS - ERA_OFFSET) {
+            Objects.requireNonNull(locale, "locale");
+            return style.asNormal() == TextStyle.NARROW ? getAbbreviation() : getName();
+        }
+        return Era.super.getDisplayName(style, locale);
+    }
+
     //-----------------------------------------------------------------------
     /**
      * Obtains an instance of {@code JapaneseEra} from a date.
@@ -338,11 +366,7 @@
 
     //-----------------------------------------------------------------------
     String getAbbreviation() {
-        int index = ordinal(getValue());
-        if (index == 0) {
-            return "";
-        }
-        return ERA_CONFIG[index].getAbbreviation();
+        return ERA_CONFIG[ordinal(getValue())].getAbbreviation();
     }
 
     String getName() {
--- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java	Mon Dec 19 09:16:40 2016 -0800
@@ -1268,10 +1268,16 @@
      * to a {@code Predicate}, and organizes them into a
      * {@code Map<Boolean, List<T>>}.
      *
+     * The returned {@code Map} always contains mappings for both
+     * {@code false} and {@code true} keys.
      * There are no guarantees on the type, mutability,
      * serializability, or thread-safety of the {@code Map} or {@code List}
      * returned.
      *
+     * @apiNote
+     * If a partition has no elements, its value in the result Map will be
+     * an empty List.
+     *
      * @param <T> the type of the input elements
      * @param predicate a predicate used for classifying input elements
      * @return a {@code Collector} implementing the partitioning operation
@@ -1290,9 +1296,17 @@
      * {@code Map<Boolean, D>} whose values are the result of the downstream
      * reduction.
      *
-     * <p>There are no guarantees on the type, mutability,
+     * <p>
+     * The returned {@code Map} always contains mappings for both
+     * {@code false} and {@code true} keys.
+     * There are no guarantees on the type, mutability,
      * serializability, or thread-safety of the {@code Map} returned.
      *
+     * @apiNote
+     * If a partition has no elements, its value in the result Map will be
+     * obtained by calling the downstream collector's supplier function and then
+     * applying the finisher function.
+     *
      * @param <T> the type of the input elements
      * @param <A> the intermediate accumulation type of the downstream collector
      * @param <D> the result type of the downstream reduction
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Mon Dec 19 09:16:40 2016 -0800
@@ -27,6 +27,8 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ReadOnlyBufferException;
+import java.util.List;
+import java.util.function.BiFunction;
 
 
 /**
@@ -1332,4 +1334,89 @@
     public String getHandshakeApplicationProtocol() {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * Registers a callback function that selects an application protocol
+     * value for a SSL/TLS/DTLS handshake.
+     * The function overrides any values set using
+     * {@link SSLParameters#setApplicationProtocols
+     * SSLParameters.setApplicationProtocols} and it supports the following
+     * type parameters:
+     * <blockquote>
+     * <dl>
+     * <dt> {@code SSLEngine}
+     * <dd> The function's first argument allows the current {@code SSLEngine}
+     *      to be inspected, including the handshake session and configuration
+     *      settings.
+     * <dt> {@code List<String>}
+     * <dd> The function's second argument lists the application protocol names
+     *      advertised by the TLS peer.
+     * <dt> {@code String}
+     * <dd> The function's result is an application protocol name, or null to
+     *      indicate that none of the advertised names are acceptable.
+     *      If the return value is null (no value chosen) or is a value that
+     *      was not advertised by the peer, the underlying protocol will
+     *      determine what action to take. (For example, ALPN will send a
+     *      "no_application_protocol" alert and terminate the connection.)
+     * </dl>
+     * </blockquote>
+     *
+     * For example, the following call registers a callback function that
+     * examines the TLS handshake parameters and selects an application protocol
+     * name:
+     * <pre>{@code
+     *     serverEngine.setHandshakeApplicationProtocolSelector(
+     *         (serverEngine, clientProtocols) -> {
+     *             SSLSession session = serverEngine.getHandshakeSession();
+     *             return chooseApplicationProtocol(
+     *                 serverEngine,
+     *                 clientProtocols,
+     *                 session.getProtocol(),
+     *                 session.getCipherSuite());
+     *         });
+     * }</pre>
+     *
+     * @apiNote
+     * This method should be called by TLS server applications before the TLS
+     * handshake begins. Also, this {@code SSLEngine} should be configured with
+     * parameters that are compatible with the application protocol selected by
+     * the callback function. For example, enabling a poor choice of cipher
+     * suites could result in no suitable application protocol.
+     * See {@link SSLParameters}.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @param selector the callback function, or null to disable the callback
+     *         functionality.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLEngine, List<String>, String> selector) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the callback function that selects an application protocol
+     * value during a SSL/TLS/DTLS handshake.
+     * See {@link #setHandshakeApplicationProtocolSelector
+     * setHandshakeApplicationProtocolSelector}
+     * for the function's type parameters.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return the callback function, or null if none has been set.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public BiFunction<SSLEngine, List<String>, String>
+            getHandshakeApplicationProtocolSelector() {
+        throw new UnsupportedOperationException();
+    }
 }
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java	Mon Dec 19 09:16:40 2016 -0800
@@ -28,6 +28,8 @@
 
 import java.io.IOException;
 import java.net.*;
+import java.util.List;
+import java.util.function.BiFunction;
 
 /**
  * This class extends <code>Socket</code>s and provides secure
@@ -742,4 +744,89 @@
     public String getHandshakeApplicationProtocol() {
         throw new UnsupportedOperationException();
     }
+
+
+    /**
+     * Registers a callback function that selects an application protocol
+     * value for a SSL/TLS/DTLS handshake.
+     * The function overrides any values set using
+     * {@link SSLParameters#setApplicationProtocols
+     * SSLParameters.setApplicationProtocols} and it supports the following
+     * type parameters:
+     * <blockquote>
+     * <dl>
+     * <dt> {@code SSLSocket}
+     * <dd> The function's first argument allows the current {@code SSLSocket}
+     *      to be inspected, including the handshake session and configuration
+     *      settings.
+     * <dt> {@code List<String>}
+     * <dd> The function's second argument lists the application protocol names
+     *      advertised by the TLS peer.
+     * <dt> {@code String}
+     * <dd> The function's result is an application protocol name, or null to
+     *      indicate that none of the advertised names are acceptable.
+     *      If the return value is null (no value chosen) or is a value that
+     *      was not advertised by the peer, the underlying protocol will
+     *      determine what action to take. (For example, ALPN will send a
+     *      "no_application_protocol" alert and terminate the connection.)
+     * </dl>
+     * </blockquote>
+     *
+     * For example, the following call registers a callback function that
+     * examines the TLS handshake parameters and selects an application protocol
+     * name:
+     * <pre>{@code
+     *     serverSocket.setHandshakeApplicationProtocolSelector(
+     *         (serverSocket, clientProtocols) -> {
+     *             SSLSession session = serverSocket.getHandshakeSession();
+     *             return chooseApplicationProtocol(
+     *                 serverSocket,
+     *                 clientProtocols,
+     *                 session.getProtocol(),
+     *                 session.getCipherSuite());
+     *         });
+     * }</pre>
+     *
+     * @apiNote
+     * This method should be called by TLS server applications before the TLS
+     * handshake begins. Also, this {@code SSLSocket} should be configured with
+     * parameters that are compatible with the application protocol selected by
+     * the callback function. For example, enabling a poor choice of cipher
+     * suites could result in no suitable application protocol.
+     * See {@link SSLParameters}.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @param selector the callback function, or null to de-register.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLSocket, List<String>, String> selector) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the callback function that selects an application protocol
+     * value during a SSL/TLS/DTLS handshake.
+     * See {@link #setHandshakeApplicationProtocolSelector
+     * setHandshakeApplicationProtocolSelector}
+     * for the function's type parameters.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return the callback function, or null if none has been set.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public BiFunction<SSLSocket, List<String>, String>
+            getHandshakeApplicationProtocolSelector() {
+        throw new UnsupportedOperationException();
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java	Mon Dec 19 09:16:40 2016 -0800
@@ -64,8 +64,10 @@
     private static final int CONSTANT_MethodHandle = 15;
     private static final int CONSTANT_MethodType = 16;
     private static final int CONSTANT_InvokeDynamic = 18;
+    private static final int CONSTANT_Module = 19;
+    private static final int CONSTANT_Package = 20;
 
-    private static final int[] SIZES = new int[20];
+    private static final int[] SIZES = new int[21];
 
     static {
 
@@ -83,6 +85,8 @@
         SIZES[CONSTANT_MethodHandle] = 3;
         SIZES[CONSTANT_MethodType] = 2;
         SIZES[CONSTANT_InvokeDynamic] = 4;
+        SIZES[CONSTANT_Module] = 2;
+        SIZES[CONSTANT_Package] = 2;
     }
 
     public static int[] getSizes() {
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Mon Dec 19 09:16:40 2016 -0800
@@ -38,10 +38,8 @@
 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;
 
@@ -59,21 +57,28 @@
      * @param strict
      *        Indicates whether module names are checked or not
      */
-    ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict);
+    ModuleDescriptor.Builder newModuleBuilder(String mn,
+                                              boolean strict,
+                                              boolean open,
+                                              boolean synthetic);
 
     /**
-     * Creates a builder for building an open module with the given module name.
-     *
-     * @param strict
-     *        Indicates whether module names are checked or not
+     * Returns the set of packages that are exported (unconditionally or
+     * unconditionally).
      */
-    ModuleDescriptor.Builder newOpenModuleBuilder(String mn, boolean strict);
+    Set<String> exportedPackages(ModuleDescriptor.Builder builder);
+
+    /**
+     * Returns the set of packages that are opened (unconditionally or
+     * unconditionally).
+     */
+    Set<String> openPackages(ModuleDescriptor.Builder builder);
 
     /**
      * Returns a {@code ModuleDescriptor.Requires} of the given modifiers
      * and module name.
      */
-    Requires newRequires(Set<Requires.Modifier> ms, String mn);
+    Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v);
 
     /**
      * Returns an unqualified {@code ModuleDescriptor.Exports}
@@ -122,6 +127,7 @@
      * Returns a new {@code ModuleDescriptor} instance.
      */
     ModuleDescriptor newModuleDescriptor(String name,
+                                         Version version,
                                          boolean open,
                                          boolean automatic,
                                          boolean synthetic,
@@ -130,21 +136,14 @@
                                          Set<Opens> opens,
                                          Set<String> uses,
                                          Set<Provides> provides,
-                                         Version version,
+                                         Set<String> packages,
                                          String mainClass,
                                          String osName,
                                          String osArch,
                                          String osVersion,
-                                         Set<String> packages,
-                                         ModuleHashes hashes,
                                          int hashCode);
 
     /**
-     * Returns the object with the hashes of other modules
-     */
-    Optional<ModuleHashes> hashes(ModuleDescriptor descriptor);
-
-    /**
      * Resolves a collection of root modules, with service binding
      * and the empty configuration as the parent. The post resolution
      * checks are optionally run.
@@ -154,18 +153,4 @@
                                          boolean check,
                                          PrintStream traceOutput);
 
-    /**
-     * Creates a ModuleReference to a "patched" module.
-     */
-    ModuleReference newPatchedModule(ModuleDescriptor descriptor,
-                                     URI location,
-                                     Supplier<ModuleReader> readerSupplier);
-
-    /**
-     * Creates a ModuleFinder for a module path.
-     */
-    ModuleFinder newModulePath(Runtime.Version version,
-                               boolean isLinkPhase,
-                               Path... entries);
-
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Mon Dec 19 09:16:40 2016 -0800
@@ -123,4 +123,12 @@
      * given class loader.
      */
     Stream<Layer> layers(ClassLoader loader);
+
+    /**
+     * Tests if a module exports a package at least {@code other} via its
+     * module declaration.
+     *
+     * @apiNote This is a temporary method for debugging features.
+     */
+    boolean isStaticallyExported(Module module, String pn, Module other);
 }
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Mon Dec 19 09:16:40 2016 -0800
@@ -30,11 +30,8 @@
 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.List;
-import java.util.Map;
 import java.util.Set;
 
 import jdk.internal.misc.JavaLangModuleAccess;
@@ -52,7 +49,7 @@
  * SystemModules should contain modules for the boot layer.
  */
 final class Builder {
-    private static final JavaLangModuleAccess jlma =
+    private static final JavaLangModuleAccess JLMA =
         SharedSecrets.getJavaLangModuleAccess();
 
     // Static cache of the most recently seen Version to cheaply deduplicate
@@ -60,13 +57,36 @@
     static Version cachedVersion;
 
     /**
-     * Returns a {@link Requires} for a dependence on a module
-     * with the given (and possibly empty) set of modifiers.
+     * Returns a {@link Requires} for a dependence on a module with the given
+     * (and possibly empty) set of modifiers, and optionally the version
+     * recorded at compile time.
+     */
+    public static Requires newRequires(Set<Requires.Modifier> mods,
+                                       String mn,
+                                       String compiledVersion)
+    {
+        Version version = null;
+        if (compiledVersion != null) {
+            // use the cached version if the same version string
+            Version ver = cachedVersion;
+            if (ver != null && compiledVersion.equals(ver.toString())) {
+                version = ver;
+            } else {
+                version = Version.parse(compiledVersion);
+            }
+        }
+        return JLMA.newRequires(mods, mn, version);
+    }
+
+    /**
+     * Returns a {@link Requires} for a dependence on a module with the given
+     * (and possibly empty) set of modifiers, and optionally the version
+     * recorded at compile time.
      */
     public static Requires newRequires(Set<Requires.Modifier> mods,
                                        String mn)
     {
-        return jlma.newRequires(mods, mn);
+        return newRequires(mods, mn, null);
     }
 
     /**
@@ -77,7 +97,7 @@
     public static Exports newExports(Set<Exports.Modifier> ms,
                                      String pn,
                                      Set<String> targets) {
-        return jlma.newExports(ms, pn, targets);
+        return JLMA.newExports(ms, pn, targets);
     }
 
     /**
@@ -85,7 +105,7 @@
      * modifiers.
      */
     public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
-        return jlma.newOpens(ms, pn);
+        return JLMA.newOpens(ms, pn);
     }
 
     /**
@@ -96,7 +116,7 @@
     public static Opens newOpens(Set<Opens.Modifier> ms,
                                  String pn,
                                  Set<String> targets) {
-        return jlma.newOpens(ms, pn, targets);
+        return JLMA.newOpens(ms, pn, targets);
     }
 
     /**
@@ -104,7 +124,7 @@
      * of modifiers.
      */
     public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
-        return jlma.newExports(ms, pn);
+        return JLMA.newExports(ms, pn);
     }
 
     /**
@@ -112,7 +132,7 @@
      * implementation classes.
      */
     public static Provides newProvides(String st, List<String> pcs) {
-        return jlma.newProvides(st, pcs);
+        return JLMA.newProvides(st, pcs);
     }
 
     final String name;
@@ -130,8 +150,6 @@
     String osName;
     String osArch;
     String osVersion;
-    String algorithm;
-    Map<String, byte[]> hashes;
 
     Builder(String name) {
         this.name = name;
@@ -275,34 +293,13 @@
     }
 
     /**
-     * Sets the algorithm of the module hashes
-     */
-    public Builder algorithm(String algorithm) {
-        this.algorithm = algorithm;
-        return this;
-    }
-
-    /**
-     * Sets the module hash for the given module name
-     */
-    public Builder moduleHash(String mn, byte[] hash) {
-        if (hashes == null)
-            hashes = new HashMap<>();
-
-        hashes.put(mn, hash);
-        return this;
-    }
-
-    /**
      * Builds a {@code ModuleDescriptor} from the components.
      */
     public ModuleDescriptor build(int hashCode) {
         assert name != null;
 
-        ModuleHashes moduleHashes =
-            hashes != null ? new ModuleHashes(algorithm, hashes) : null;
-
-        return jlma.newModuleDescriptor(name,
+        return JLMA.newModuleDescriptor(name,
+                                        version,
                                         open,
                                         automatic,
                                         synthetic,
@@ -311,13 +308,11 @@
                                         opens,
                                         uses,
                                         provides,
-                                        version,
+                                        packages,
                                         mainClass,
                                         osName,
                                         osArch,
                                         osVersion,
-                                        packages,
-                                        moduleHashes,
                                         hashCode);
     }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java	Mon Dec 19 09:16:40 2016 -0800
@@ -25,79 +25,200 @@
 
 package jdk.internal.module;
 
+/**
+ * Utility class for checking module name and binary names.
+ */
+
 public final class Checks {
 
     private Checks() { }
 
-    private static void fail(String what, String id, int i) {
-        throw new IllegalArgumentException(id
-                                           + ": Invalid " + what + ": "
-                                           + " Illegal character"
-                                           + " at index " + i);
+    /**
+     * Checks a name to ensure that it's a legal module name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         module name
+     */
+    public static String requireModuleName(String name) {
+        if (name == null)
+            throw new IllegalArgumentException("Null module name");
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1) {
+                String id = name.substring(off, next);
+                throw new IllegalArgumentException(name + ": Invalid module name"
+                        + ": '" + id + "' is not a Java identifier");
+            }
+            off = next+1;
+        }
+        int last = isJavaIdentifier(name, off, name.length() - off);
+        if (last == -1) {
+            String id = name.substring(off);
+            throw new IllegalArgumentException(name + ": Invalid module name"
+                    + ": '" + id + "' is not a Java identifier");
+        }
+        //if (!Character.isJavaIdentifierStart(last))
+        //    throw new IllegalArgumentException(name + ": Module name ends in digit");
+        return name;
     }
 
     /**
-     * Returns {@code true} if the given identifier is a legal Java identifier.
+     * Returns {@code true} if the given name is a legal module name.
      */
-    public static boolean isJavaIdentifier(String id) {
-        int n = id.length();
-        if (n == 0)
+    public static boolean isModuleName(String name) {
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1)
+                return false;
+            off = next+1;
+        }
+        int last = isJavaIdentifier(name, off, name.length() - off);
+        if (last == -1)
             return false;
-        if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
-            return false;
-        int cp = id.codePointAt(0);
-        int i = Character.charCount(cp);
-        for (; i < n; i += Character.charCount(cp)) {
-            cp = id.codePointAt(i);
-            if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
-                return false;
-        }
-        if (cp == '.')
-            return false;
-
+        //if (!Character.isJavaIdentifierStart(last))
+        //    return false;
         return true;
     }
 
     /**
-     * Checks if a given identifier is a legal Java identifier.
+     * Checks a name to ensure that it's a legal package name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         package name
      */
-    public static String requireJavaIdentifier(String what, String id) {
-        if (id == null)
-            throw new IllegalArgumentException("Null " + what);
-        int n = id.length();
-        if (n == 0)
-            throw new IllegalArgumentException("Empty " + what);
-        if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
-            fail(what, id, 0);
-        int cp = id.codePointAt(0);
-        int i = Character.charCount(cp);
-        int last = 0;
-        for (; i < n; i += Character.charCount(cp)) {
-            cp = id.codePointAt(i);
-            if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
-                fail(what, id, i);
-            last = i;
-        }
-        if (cp == '.')
-            fail(what, id, last);
-
-        return id;
+    public static String requirePackageName(String name) {
+        return requireBinaryName("package name", name);
     }
 
-    public static String requireModuleName(String id) {
-        return requireJavaIdentifier("module name", id);
+    /**
+     * Checks a name to ensure that it's a legal type name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         type name
+     */
+    public static String requireServiceTypeName(String name) {
+        return requireBinaryName("service type name", name);
     }
 
-    public static String requirePackageName(String id) {
-        return requireJavaIdentifier("package name", id);
+    /**
+     * Checks a name to ensure that it's a legal type name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         type name
+     */
+    public static String requireServiceProviderName(String name) {
+        return requireBinaryName("service provider name", name);
     }
 
-    public static String requireServiceTypeName(String id) {
-        return requireJavaIdentifier("service type name", id);
+    /**
+     * Returns {@code true} if the given name is a legal binary name.
+     */
+    public static boolean isJavaIdentifier(String name) {
+        return isBinaryName(name);
     }
 
-    public static String requireServiceProviderName(String id) {
-        return requireJavaIdentifier("service provider name", id);
+    /**
+     * Returns {@code true} if the given name is a legal binary name.
+     */
+    public static boolean isBinaryName(String name) {
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1)
+                return false;
+            off = next+1;
+        }
+        int count = name.length() - off;
+        return (isJavaIdentifier(name, off, count) != -1);
     }
 
+    /**
+     * Checks if the given name is a legal binary name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         binary name
+     */
+    public static String requireBinaryName(String what, String name) {
+        if (name == null)
+            throw new IllegalArgumentException("Null " + what);
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1) {
+                String id = name.substring(off, next);
+                throw new IllegalArgumentException(name + ": Invalid " + what
+                        + ": '" + id + "' is not a Java identifier");
+            }
+            off = next + 1;
+        }
+        if (isJavaIdentifier(name, off, name.length() - off) == -1) {
+            String id = name.substring(off, name.length());
+            throw new IllegalArgumentException(name + ": Invalid " + what
+                    + ": '" + id + "' is not a Java identifier");
+        }
+        return name;
+    }
+
+    /**
+     * Returns {@code true} if the last character of the given name is legal
+     * as the last character of a module name.
+     *
+     * @throws IllegalArgumentException if name is empty
+     */
+    public static boolean hasLegalModuleNameLastCharacter(String name) {
+        if (name.isEmpty())
+            throw new IllegalArgumentException("name is empty");
+        int len = name.length();
+        if (isASCIIString(name)) {
+            char c = name.charAt(len-1);
+            return Character.isJavaIdentifierStart(c);
+        } else {
+            int i = 0;
+            int cp = -1;
+            while (i < len) {
+                cp = name.codePointAt(i);
+                i += Character.charCount(cp);
+            }
+            return Character.isJavaIdentifierStart(cp);
+        }
+    }
+
+    /**
+     * Returns true if the given string only contains ASCII characters.
+     */
+    private static boolean isASCIIString(String s) {
+        int i = 0;
+        while (i < s.length()) {
+            int c = s.charAt(i);
+            if (c > 0x7F)
+                return false;
+            i++;
+        }
+        return true;
+    }
+
+    /**
+     * Checks if a char sequence is a legal Java identifier, returning the code
+     * point of the last character if legal or {@code -1} if not legal.
+     */
+    private static int isJavaIdentifier(CharSequence cs, int offset, int count) {
+        if (count == 0)
+            return -1;
+        int first = Character.codePointAt(cs, offset);
+        if (!Character.isJavaIdentifierStart(first))
+            return -1;
+
+        int cp = first;
+        int i = Character.charCount(first);
+        while (i < count) {
+            cp = Character.codePointAt(cs, offset+i);
+            if (!Character.isJavaIdentifierPart(cp))
+                return -1;
+            i += Character.charCount(cp);
+        }
+
+        return cp;
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Mon Dec 19 09:16:40 2016 -0800
@@ -68,12 +68,18 @@
             = SharedSecrets.getJavaLangModuleAccess();
 
         private ModuleDescriptor descriptor;
+        private Version replacementVersion;
 
         public ModuleAttribute(ModuleDescriptor descriptor) {
             super(MODULE);
             this.descriptor = descriptor;
         }
 
+        public ModuleAttribute(Version v) {
+            super(MODULE);
+            this.replacementVersion = v;
+        }
+
         public ModuleAttribute() {
             super(MODULE);
         }
@@ -86,46 +92,70 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            ModuleAttribute attr = new ModuleAttribute();
-
-            // module_name
-            String mn = cr.readUTF8(off, buf).replace('/', '.');
+            // module_name (CONSTANT_Module_info)
+            String mn = cr.readModule(off, buf);
             off += 2;
 
             // module_flags
             int module_flags = cr.readUnsignedShort(off);
             boolean open = ((module_flags & ACC_OPEN) != 0);
+            boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
             off += 2;
 
-            ModuleDescriptor.Builder builder;
-            if (open) {
-                builder = JLMA.newOpenModuleBuilder(mn, false);
-            } else {
-                builder = JLMA.newModuleBuilder(mn, false);
+            ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn,
+                                                                     false,
+                                                                     open,
+                                                                     synthetic);
+
+            // module_version
+            String module_version = cr.readUTF8(off, buf);
+            off += 2;
+            if (replacementVersion != null) {
+                builder.version(replacementVersion);
+            } else if (module_version != null) {
+                builder.version(module_version);
             }
 
             // 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).replace('/', '.');
-                int flags = cr.readUnsignedShort(off + 2);
+                // CONSTANT_Module_info
+                String dn = cr.readModule(off, buf);
+                off += 2;
+
+                // requires_flags
+                int requires_flags = cr.readUnsignedShort(off);
+                off += 2;
                 Set<Requires.Modifier> mods;
-                if (flags == 0) {
+                if (requires_flags == 0) {
                     mods = Collections.emptySet();
                 } else {
                     mods = new HashSet<>();
-                    if ((flags & ACC_TRANSITIVE) != 0)
+                    if ((requires_flags & ACC_TRANSITIVE) != 0)
                         mods.add(Requires.Modifier.TRANSITIVE);
-                    if ((flags & ACC_STATIC_PHASE) != 0)
+                    if ((requires_flags & ACC_STATIC_PHASE) != 0)
                         mods.add(Requires.Modifier.STATIC);
-                    if ((flags & ACC_SYNTHETIC) != 0)
+                    if ((requires_flags & ACC_SYNTHETIC) != 0)
                         mods.add(Requires.Modifier.SYNTHETIC);
-                    if ((flags & ACC_MANDATED) != 0)
+                    if ((requires_flags & ACC_MANDATED) != 0)
                         mods.add(Requires.Modifier.MANDATED);
                 }
-                builder.requires(mods, dn);
-                off += 4;
+
+
+                // requires_version
+                Version compiledVersion = null;
+                String requires_version = cr.readUTF8(off, buf);
+                off += 2;
+                if (requires_version != null) {
+                    compiledVersion = Version.parse(requires_version);
+                }
+
+                if (compiledVersion == null) {
+                    builder.requires(mods, dn);
+                } else {
+                    builder.requires(mods, dn, compiledVersion);
+                }
             }
 
             // exports_count and exports[exports_count]
@@ -133,19 +163,20 @@
             off += 2;
             if (exports_count > 0) {
                 for (int i=0; i<exports_count; i++) {
-                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    // CONSTANT_Package_info
+                    String pkg = cr.readPackage(off, buf).replace('/', '.');
                     off += 2;
 
-                    int flags = cr.readUnsignedShort(off);
+                    int exports_flags = cr.readUnsignedShort(off);
                     off += 2;
                     Set<Exports.Modifier> mods;
-                    if (flags == 0) {
+                    if (exports_flags == 0) {
                         mods = Collections.emptySet();
                     } else {
                         mods = new HashSet<>();
-                        if ((flags & ACC_SYNTHETIC) != 0)
+                        if ((exports_flags & ACC_SYNTHETIC) != 0)
                             mods.add(Exports.Modifier.SYNTHETIC);
-                        if ((flags & ACC_MANDATED) != 0)
+                        if ((exports_flags & ACC_MANDATED) != 0)
                             mods.add(Exports.Modifier.MANDATED);
                     }
 
@@ -154,7 +185,7 @@
                     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).replace('/', '.');
+                            String t = cr.readModule(off, buf);
                             off += 2;
                             targets.add(t);
                         }
@@ -170,19 +201,20 @@
             off += 2;
             if (open_count > 0) {
                 for (int i=0; i<open_count; i++) {
-                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    // CONSTANT_Package_info
+                    String pkg = cr.readPackage(off, buf).replace('/', '.');
                     off += 2;
 
-                    int flags = cr.readUnsignedShort(off);
+                    int opens_flags = cr.readUnsignedShort(off);
                     off += 2;
                     Set<Opens.Modifier> mods;
-                    if (flags == 0) {
+                    if (opens_flags == 0) {
                         mods = Collections.emptySet();
                     } else {
                         mods = new HashSet<>();
-                        if ((flags & ACC_SYNTHETIC) != 0)
+                        if ((opens_flags & ACC_SYNTHETIC) != 0)
                             mods.add(Opens.Modifier.SYNTHETIC);
-                        if ((flags & ACC_MANDATED) != 0)
+                        if ((opens_flags & ACC_MANDATED) != 0)
                             mods.add(Opens.Modifier.MANDATED);
                     }
 
@@ -191,7 +223,7 @@
                     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('/', '.');
+                            String t = cr.readModule(off, buf);
                             off += 2;
                             targets.add(t);
                         }
@@ -232,8 +264,7 @@
                 }
             }
 
-            attr.descriptor = builder.build();
-            return attr;
+            return new ModuleAttribute(builder.build());
         }
 
         @Override
@@ -248,7 +279,7 @@
 
             // module_name
             String mn = descriptor.name();
-            int module_name_index = cw.newUTF8(mn.replace('.', '/'));
+            int module_name_index = cw.newModule(mn);
             attr.putShort(module_name_index);
 
             // module_flags
@@ -259,66 +290,83 @@
                 module_flags |= ACC_SYNTHETIC;
             attr.putShort(module_flags);
 
+            // module_version
+            Version v = descriptor.version().orElse(null);
+            if (v == null) {
+                attr.putShort(0);
+            } else {
+                int module_version_index = cw.newUTF8(v.toString());
+                attr.putShort(module_version_index);
+            }
+
             // requires_count
             attr.putShort(descriptor.requires().size());
 
             // requires[requires_count]
-            for (Requires md : descriptor.requires()) {
-                String dn = md.name();
-                int flags = 0;
-                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(Requires.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                int index = cw.newUTF8(dn.replace('.', '/'));
-                attr.putShort(index);
-                attr.putShort(flags);
+            for (Requires r : descriptor.requires()) {
+                int requires_index = cw.newModule(r.name());
+                attr.putShort(requires_index);
+
+                int requires_flags = 0;
+                if (r.modifiers().contains(Requires.Modifier.TRANSITIVE))
+                    requires_flags |= ACC_TRANSITIVE;
+                if (r.modifiers().contains(Requires.Modifier.STATIC))
+                    requires_flags |= ACC_STATIC_PHASE;
+                if (r.modifiers().contains(Requires.Modifier.SYNTHETIC))
+                    requires_flags |= ACC_SYNTHETIC;
+                if (r.modifiers().contains(Requires.Modifier.MANDATED))
+                    requires_flags |= ACC_MANDATED;
+                attr.putShort(requires_flags);
+
+                int requires_version_index;
+                v = r.compiledVersion().orElse(null);
+                if (v == null) {
+                    requires_version_index = 0;
+                } else {
+                    requires_version_index = cw.newUTF8(v.toString());
+                }
+                attr.putShort(requires_version_index);
             }
 
             // exports_count and exports[exports_count];
             attr.putShort(descriptor.exports().size());
             for (Exports e : descriptor.exports()) {
                 String pkg = e.source().replace('.', '/');
-                attr.putShort(cw.newUTF8(pkg));
+                attr.putShort(cw.newPackage(pkg));
 
-                int flags = 0;
+                int exports_flags = 0;
                 if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
-                    flags |= ACC_SYNTHETIC;
+                    exports_flags |= ACC_SYNTHETIC;
                 if (e.modifiers().contains(Exports.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                attr.putShort(flags);
+                    exports_flags |= ACC_MANDATED;
+                attr.putShort(exports_flags);
 
                 if (e.isQualified()) {
                     Set<String> ts = e.targets();
                     attr.putShort(ts.size());
-                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                    ts.forEach(target -> attr.putShort(cw.newModule(target)));
                 } 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));
+                attr.putShort(cw.newPackage(pkg));
 
-                int flags = 0;
+                int opens_flags = 0;
                 if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
-                    flags |= ACC_SYNTHETIC;
+                    opens_flags |= ACC_SYNTHETIC;
                 if (obj.modifiers().contains(Opens.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                attr.putShort(flags);
+                    opens_flags |= ACC_MANDATED;
+                attr.putShort(opens_flags);
 
                 if (obj.isQualified()) {
                     Set<String> ts = obj.targets();
                     attr.putShort(ts.size());
-                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                    ts.forEach(target -> attr.putShort(cw.newModule(target)));
                 } else {
                     attr.putShort(0);
                 }
@@ -369,7 +417,7 @@
      *
      *   // the number of entries in the packages table
      *   u2 packages_count;
-     *   { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
+     *   { // index to CONSTANT_Package_info structure with the package name
      *     u2 package_index
      *   } packages[package_count];
      *
@@ -402,7 +450,7 @@
             // packages
             Set<String> packages = new HashSet<>();
             for (int i=0; i<package_count; i++) {
-                String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                String pkg = cr.readPackage(off, buf).replace('/', '.');
                 packages.add(pkg);
                 off += 2;
             }
@@ -427,7 +475,7 @@
             // packages
             packages.stream()
                 .map(p -> p.replace('.', '/'))
-                .forEach(p -> attr.putShort(cw.newUTF8(p)));
+                .forEach(p -> attr.putShort(cw.newPackage(p)));
 
             return attr;
         }
@@ -435,61 +483,6 @@
     }
 
     /**
-     * ModuleVersion attribute.
-     *
-     * <pre> {@code
-     *
-     * ModuleVersion_attribute {
-     *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ModuleVersion"
-     *   u2 attribute_name_index;
-     *   u4 attribute_length;
-     *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the version
-     *   u2 version_index;
-     * }
-     *
-     * } </pre>
-     */
-    public static class ModuleVersionAttribute extends Attribute {
-        private final Version version;
-
-        public ModuleVersionAttribute(Version version) {
-            super(MODULE_VERSION);
-            this.version = version;
-        }
-
-        public ModuleVersionAttribute() {
-            this(null);
-        }
-
-        @Override
-        protected Attribute read(ClassReader cr,
-                                 int off,
-                                 int len,
-                                 char[] buf,
-                                 int codeOff,
-                                 Label[] labels)
-        {
-            String value = cr.readUTF8(off, buf);
-            return new ModuleVersionAttribute(Version.parse(value));
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            ByteVector attr = new ByteVector();
-            int index = cw.newUTF8(version.toString());
-            attr.putShort(index);
-            return attr;
-        }
-    }
-
-    /**
      * ModuleMainClass attribute.
      *
      * <pre> {@code
@@ -526,7 +519,7 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            String value = cr.readClass(off, buf);
+            String value = cr.readClass(off, buf).replace('/', '.');
             return new ModuleMainClassAttribute(value);
         }
 
@@ -538,7 +531,7 @@
                                    int maxLocals)
         {
             ByteVector attr = new ByteVector();
-            int index = cw.newClass(mainClass);
+            int index = cw.newClass(mainClass.replace('.', '/'));
             attr.putShort(index);
             return attr;
         }
@@ -555,11 +548,11 @@
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
+     *   // index to CONSTANT_utf8_info structure with the OS name
      *   u2 os_name_index;
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
+     *   // index to CONSTANT_utf8_info structure with the OS arch
      *   u2 os_arch_index
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
+     *   // index to CONSTANT_utf8_info structure with the OS version
      *   u2 os_version_index;
      * }
      *
@@ -656,7 +649,7 @@
      *
      *   // the number of entries in the hashes table
      *   u2 hashes_count;
-     *   {   u2 module_name_index
+     *   {   u2 module_name_index (index to CONSTANT_Module_info structure)
      *       u2 hash_length;
      *       u1 hash[hash_length];
      *   } hashes[hashes_count];
@@ -691,7 +684,7 @@
 
             Map<String, byte[]> map = new HashMap<>();
             for (int i=0; i<hashes_count; i++) {
-                String mn = cr.readUTF8(off, buf).replace('/', '.');
+                String mn = cr.readModule(off, buf);
                 off += 2;
 
                 int hash_length = cr.readUnsignedShort(off);
@@ -728,7 +721,7 @@
             for (String mn : names) {
                 byte[] hash = hashes.hashFor(mn);
                 assert hash != null;
-                attr.putShort(cw.newUTF8(mn.replace('.', '/')));
+                attr.putShort(cw.newModule(mn));
 
                 attr.putShort(hash.length);
                 for (byte b: hash) {
@@ -740,4 +733,58 @@
         }
     }
 
+    /**
+     *  ModuleResolution_attribute {
+     *    u2 attribute_name_index;    // "ModuleResolution"
+     *    u4 attribute_length;        // 2
+     *    u2 resolution_flags;
+     *
+     *  The value of the resolution_flags item is a mask of flags used to denote
+     *  properties of module resolution. The flags are as follows:
+     *
+     *   // Optional
+     *   0x0001 (DO_NOT_RESOLVE_BY_DEFAULT)
+     *
+     *   // At most one of:
+     *   0x0002 (WARN_DEPRECATED)
+     *   0x0004 (WARN_DEPRECATED_FOR_REMOVAL)
+     *   0x0008 (WARN_INCUBATING)
+     */
+    static class ModuleResolutionAttribute extends Attribute {
+        private final int value;
+
+        ModuleResolutionAttribute() {
+            super(MODULE_RESOLUTION);
+            value = 0;
+        }
+
+        ModuleResolutionAttribute(int value) {
+            super(MODULE_RESOLUTION);
+            this.value = value;
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            int flags = cr.readUnsignedShort(off);
+            return new ModuleResolutionAttribute(flags);
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            ByteVector attr = new ByteVector();
+            attr.putShort(value);
+            return attr;
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Mon Dec 19 09:16:40 2016 -0800
@@ -38,10 +38,10 @@
     public static final String SDE                = "SourceDebugExtension";
 
     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";
+    public static final String MODULE_RESOLUTION  = "ModuleResolution";
 
     // access, requires, exports, and opens flags
     public static final int ACC_MODULE        = 0x8000;
@@ -51,4 +51,10 @@
     public static final int ACC_SYNTHETIC     = 0x1000;
     public static final int ACC_MANDATED      = 0x8000;
 
+    // ModuleResolution_attribute resolution flags
+    public static final int DO_NOT_RESOLVE_BY_DEFAULT   = 0x0001;
+    public static final int WARN_DEPRECATED             = 0x0002;
+    public static final int WARN_DEPRECATED_FOR_REMOVAL = 0x0004;
+    public static final int WARN_INCUBATING             = 0x0008;
+
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Mon Dec 19 09:16:40 2016 -0800
@@ -195,7 +195,9 @@
         // module is the unnamed module of the application class loader. This
         // is implemented by resolving "java.se" and all (non-java.*) modules
         // that export an API. If "java.se" is not observable then all java.*
-        // modules are resolved.
+        // modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
+        // bit set in their ModuleResolution attribute flags are excluded from
+        // the default set of roots.
         if (mainModule == null || addAllDefaultModules) {
             boolean hasJava = false;
             if (systemModules.find(JAVA_SE).isPresent()) {
@@ -212,6 +214,9 @@
                 if (hasJava && mn.startsWith("java."))
                     continue;
 
+                if (ModuleResolution.doNotResolveByDefault(mref))
+                    continue;
+
                 // add as root if observable and exports at least one package
                 if ((finder == systemModules || finder.find(mn).isPresent())) {
                     ModuleDescriptor descriptor = mref.descriptor();
@@ -231,6 +236,7 @@
             ModuleFinder f = finder;  // observable modules
             systemModules.findAll()
                 .stream()
+                .filter(mref -> !ModuleResolution.doNotResolveByDefault(mref))
                 .map(ModuleReference::descriptor)
                 .map(ModuleDescriptor::name)
                 .filter(mn -> f.find(mn).isPresent())  // observable
@@ -277,6 +283,8 @@
         // time to create configuration
         PerfCounters.resolveTime.addElapsedTimeFrom(t3);
 
+        // check module names and incubating status
+        checkModuleNamesAndStatus(cf);
 
         // mapping of modules to class loaders
         Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
@@ -508,12 +516,12 @@
             String key = e.getKey();
             String[] s = key.split("/");
             if (s.length != 2)
-                fail("Unable to parse: " + key);
+                fail("Unable to parse as <module>/<package>: " + key);
 
             String mn = s[0];
             String pn = s[1];
             if (mn.isEmpty() || pn.isEmpty())
-                fail("Module and package name must be specified:" + key);
+                fail("Module and package name must be specified: " + key);
 
             // The exporting module is in the boot layer
             Module m;
@@ -585,7 +593,7 @@
 
             int pos = value.indexOf('=');
             if (pos == -1)
-                fail("Unable to parse: " + value);
+                fail("Unable to parse as <module>=<value>: " + value);
             if (pos == 0)
                 fail("Missing module name in: " + value);
 
@@ -594,7 +602,7 @@
 
             String rhs = value.substring(pos+1);
             if (rhs.isEmpty())
-                fail("Unable to parse: " + value);
+                fail("Unable to parse as <module>=<value>: " + value);
 
             // value is <module>(,<module>)* or <file>(<pathsep><file>)*
             if (!allowDuplicates && map.containsKey(key))
@@ -627,6 +635,33 @@
     }
 
     /**
+     * Checks the names and resolution bit of each module in the configuration,
+     * emitting warnings if needed.
+     */
+    private static void checkModuleNamesAndStatus(Configuration cf) {
+        String incubating = null;
+        for (ResolvedModule rm : cf.modules()) {
+            ModuleReference mref = rm.reference();
+            String mn = mref.descriptor().name();
+
+            // emit warning if module name ends with a non-Java letter
+            if (!Checks.hasLegalModuleNameLastCharacter(mn))
+                warn("Module name \"" + mn + "\" may soon be illegal");
+
+            // emit warning if the WARN_INCUBATING module resolution bit set
+            if (ModuleResolution.hasIncubatingWarning(mref)) {
+                if (incubating == null) {
+                    incubating = mn;
+                } else {
+                    incubating += ", " + mn;
+                }
+            }
+        }
+        if (incubating != null)
+            warn("Using incubator modules: " + incubating);
+    }
+
+    /**
      * Throws a RuntimeException with the given message
      */
     static void fail(String m) {
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Tue Dec 06 14:54:11 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Mon Dec 19 09:16:40 2016 -0800
@@ -35,6 +35,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -50,7 +51,6 @@
         byte[] generate(String algorithm);
     }
 
-
     private final String algorithm;
     private final Map<String, byte[]> nameToHash;
 
@@ -142,4 +142,37 @@
         }
         return new ModuleHashes(algorithm, nameToHash);
     }
+
+    /**
+     * This is used by jdk.internal.module.SystemModules class
+     * generated at link time.
+     */
+    public static class Builder {
+        final String algorithm;
+        final Map<String, byte[]> nameToHash;
+
+        Builder(String algorithm, int initialCapacity) {
+            this.nameToHash = new HashMap<>(initialCapacity);
+            this.algorithm =  Objects.requireNonNull(algorithm);
+        }
+
+        /**
+         * Sets the module hash for the given module name
+         */
+        public Builder hashForModule(String mn, byte[] hash) {
+            nameToHash.put(mn, hash);
+            return this;
+        }
+
+        /**
+         * Builds a {@code ModuleHashes}.
+         */
+        public ModuleHashes build() {
+            if (!nameToHash.isEmpty()) {
+                return new ModuleHashes(algorithm, nameToHash);
+            } else {
+                return null;
+            }
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java	Mon Dec 19 09:16:40 2016 -0800
@@ -0,0 +1,1089 @@
+/*
+ * 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
+ * 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.module;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+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.lang.module.ModuleDescriptor.Version;
+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.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleResolution;
+
+import static jdk.internal.module.ClassFileConstants.*;
+
+
+/**
+ * Read module information from a {@code module-info} class file.
+ *
+ * @implNote The rationale for the hand-coded reader is startup performance
+ * and fine control over the throwing of InvalidModuleDescriptorException.
+ */
+
+public final class ModuleInfo {
+
+    private static final JavaLangModuleAccess JLMA
+        = SharedSecrets.getJavaLangModuleAccess();
+
+    // supplies the set of packages when ModulePackages attribute not present
+    private final Supplier<Set<String>> packageFinder;
+
+    // indicates if the ModuleHashes attribute should be parsed
+    private final boolean parseHashes;
+
+    private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
+        packageFinder = pf;
+        parseHashes = ph;
+    }
+
+    private ModuleInfo(Supplier<Set<String>> pf) {
+        this(pf, true);
+    }
+
+    /**
+     * A holder class for the ModuleDescriptor that is created by reading the
+     * Module and other standard class file attributes. It also holds the objects
+     * that represent the non-standard class file attributes that are read from
+     * the class file.
+     */
+    public static final class Attributes {
+        private final ModuleDescriptor descriptor;
+        private final ModuleHashes recordedHashes;
+        private final ModuleResolution moduleResolution;
+        Attributes(ModuleDescriptor descriptor,
+                   ModuleHashes recordedHashes,
+                   ModuleResolution moduleResolution) {
+            this.descriptor = descriptor;
+            this.recordedHashes = recordedHashes;
+            this.moduleResolution = moduleResolution;
+        }
+        public ModuleDescriptor descriptor() {
+            return descriptor;
+        }
+        public ModuleHashes recordedHashes() {
+            return recordedHashes;
+        }
+        public ModuleResolution moduleResolution() {
+            return moduleResolution;
+        }
+    }
+
+
+    /**
+     * Reads a {@code module-info.class} from the given input stream.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws IOException
+     */
+    public static Attributes read(InputStream in, Supplier<Set<String>> pf)
+        throws IOException
+    {
+        try {
+            return new ModuleInfo(pf).doRead(new DataInputStream(in));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        }
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given byte buffer.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws UncheckedIOException
+     */
+    public static Attributes read(ByteBuffer bb, Supplier<Set<String>> pf) {
+        try {
+            return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given byte buffer
+     * but ignore the {@code ModuleHashes} attribute.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws UncheckedIOException
+     */
+    public static Attributes readIgnoringHashes(ByteBuffer bb, Supplier<Set<String>> pf) {
+        try {
+            return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Reads the input as a module-info class file.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
+     * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
+     *         because an identifier is not a legal Java identifier, duplicate
+     *         exports, and many other reasons
+     */
+    private Attributes doRead(DataInput in) throws IOException {
+
+        int magic = in.readInt();
+        if (magic != 0xCAFEBABE)
+            throw invalidModuleDescriptor("Bad magic number");
+
+        int minor_version = in.readUnsignedShort();
+        int major_version = in.readUnsignedShort();
+        if (major_version < 53) {
+            throw invalidModuleDescriptor("Must be >= 53.0");
+        }
+
+        ConstantPool cpool = new ConstantPool(in);
+
+        int access_flags = in.readUnsignedShort();
+        if (access_flags != ACC_MODULE)
+            throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
+
+        int this_class = in.readUnsignedShort();
+        String mn = cpool.getClassName(this_class);
+        if (!"module-info".equals(mn))
+            throw invalidModuleDescriptor("this_class should be module-info");
+
+        int super_class = in.readUnsignedShort();
+        if (super_class > 0)
+            throw invalidModuleDescriptor("bad #super_class");
+
+        int interfaces_count = in.readUnsignedShort();
+        if (interfaces_count > 0)
+            throw invalidModuleDescriptor("Bad #interfaces");
+
+        int fields_count = in.readUnsignedShort();
+        if (fields_count > 0)
+            throw invalidModuleDescriptor("Bad #fields");
+
+        int methods_count = in.readUnsignedShort();
+        if (methods_count > 0)
+            throw invalidModuleDescriptor("Bad #methods");
+
+        int attributes_count = in.readUnsignedShort();
+
+        // the names of the attributes found in the class file
+        Set<String> attributes = new HashSet<>();
+
+        Builder builder = null;
+        Set<String> packages = null;
+        String mainClass = null;
+        String[] osValues = null;
+        ModuleHashes hashes = null;
+        ModuleResolution moduleResolution = null;
+
+        for (int i = 0; i < attributes_count ; i++) {
+            int name_index = in.readUnsignedShort();
+            String attribute_name = cpool.getUtf8(name_index);
+            int length = in.readInt();
+
+            boolean added = attributes.add(attribute_name);
+            if (!added && isAttributeAtMostOnce(attribute_name)) {
+                throw invalidModuleDescriptor("More than one "
+                                              + attribute_name + " attribute");
+            }
+
+            switch (attribute_name) {
+
+                case MODULE :
+                    builder = readModuleAttribute(in, cpool);
+                    break;
+
+                case MODULE_PACKAGES :
+                    packages = readModulePackagesAttribute(in, cpool);
+                    break;
+
+                case MODULE_MAIN_CLASS :
+                    mainClass = readModuleMainClassAttribute(in, cpool);
+                    break;
+
+                case MODULE_TARGET :
+                    osValues = readModuleTargetAttribute(in, cpool);
+                    break;
+
+                case MODULE_HASHES :
+                    if (parseHashes) {
+                        hashes = readModuleHashesAttribute(in, cpool);
+                    } else {
+                        in.skipBytes(length);
+                    }
+                    break;
+
+                case MODULE_RESOLUTION :
+                    moduleResolution = readModuleResolution(in, cpool);
+                    break;
+
+                default:
+                    if (isAttributeDisallowed(attribute_name)) {
+                        throw invalidModuleDescriptor(attribute_name
+                                                      + " attribute not allowed");
+                    } else {
+                        in.skipBytes(length);
+                    }
+
+            }
+        }
+
+        // the Module attribute is required
+        if (builder == null) {
+            throw invalidModuleDescriptor(MODULE + " attribute not found");
+        }
+
+        // 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 {
+                packages = new HashSet<>(packageFinder.get());
+            } catch (UncheckedIOException x) {
+                throw x.getCause();
+            }
+            usedPackageFinder = true;
+        }
+        if (packages != null) {
+            Set<String> exportedPackages = JLMA.exportedPackages(builder);
+            Set<String> openPackages = JLMA.openPackages(builder);
+            if (packages.containsAll(exportedPackages)
+                    && packages.containsAll(openPackages)) {
+                packages.removeAll(exportedPackages);
+                packages.removeAll(openPackages);
+            } else {
+                // the set of packages is not complete
+                Set<String> exportedAndOpenPackages = new HashSet<>();
+                exportedAndOpenPackages.addAll(exportedPackages);
+                exportedAndOpenPackages.addAll(openPackages);
+                for (String pn : 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);
+                    }
+                }
+                assert false; // should not get here
+            }
+            builder.contains(packages);
+        }
+
+        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]);
+        }
+
+        ModuleDescriptor descriptor = builder.build();
+        return new Attributes(descriptor, hashes, moduleResolution);
+    }
+
+    /**
+     * Reads the Module attribute, returning the ModuleDescriptor.Builder to
+     * build the corresponding ModuleDescriptor.
+     */
+    private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        // module_name
+        int module_name_index = in.readUnsignedShort();
+        String mn = cpool.getModuleName(module_name_index);
+
+        int module_flags = in.readUnsignedShort();
+        boolean open = ((module_flags & ACC_OPEN) != 0);
+        boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
+
+        Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic);
+
+        int module_version_index = in.readUnsignedShort();
+        if (module_version_index != 0) {
+            String vs = cpool.getUtf8(module_version_index);
+            builder.version(vs);
+        }
+
+        int requires_count = in.readUnsignedShort();
+        boolean requiresJavaBase = false;
+        for (int i=0; i<requires_count; i++) {
+            int requires_index = in.readUnsignedShort();
+            String dn = cpool.getModuleName(requires_index);
+
+            int requires_flags = in.readUnsignedShort();
+            Set<Requires.Modifier> mods;
+            if (requires_flags == 0) {
+                mods = Collections.emptySet();
+            } else {
+                mods = new HashSet<>();
+                if ((requires_flags & ACC_TRANSITIVE) != 0)
+                    mods.add(Requires.Modifier.TRANSITIVE);
+                if ((requires_flags & ACC_STATIC_PHASE) != 0)
+                    mods.add(Requires.Modifier.STATIC);
+                if ((requires_flags & ACC_SYNTHETIC) != 0)
+                    mods.add(Requires.Modifier.SYNTHETIC);
+                if ((requires_flags & ACC_MANDATED) != 0)
+                    mods.add(Requires.Modifier.MANDATED);
+            }
+
+            int requires_version_index = in.readUnsignedShort();
+            Version compiledVersion = null;
+            if (requires_version_index != 0) {
+                String vs = cpool.getUtf8(requires_version_index);
+                compiledVersion = Version.parse(vs);
+            }
+
+            if (compiledVersion == null) {
+                builder.requires(mods, dn);
+            } else {
+                builder.requires(mods, dn, compiledVersion);
+            }
+
+            if (dn.equals("java.base"))
+                requiresJavaBase = true;
+        }
+        if (mn.equals("java.base")) {
+            if (requires_count > 0) {
+                throw invalidModuleDescriptor("The requires table for java.base"
+                                              + " must be 0 length");
+            }
+        } else if (!requiresJavaBase) {
+            throw invalidModuleDescriptor("The requires table must have"
+                                          + " an entry for java.base");
+        }
+
+        int exports_count = in.readUnsignedShort();
+        if (exports_count > 0) {
+            for (int i=0; i<exports_count; i++) {
+                int exports_index = in.readUnsignedShort();
+                String pkg = cpool.getPackageName(exports_index);
+
+                Set<Exports.Modifier> mods;
+                int exports_flags = in.readUnsignedShort();
+                if (exports_flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((exports_flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Exports.Modifier.SYNTHETIC);
+                    if ((exports_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.getModuleName(exports_to_index));
+                    }
+                    builder.exports(mods, pkg, targets);
+                } else {
+                    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 opens_index = in.readUnsignedShort();
+                String pkg = cpool.getPackageName(opens_index);
+
+                Set<Opens.Modifier> mods;
+                int opens_flags = in.readUnsignedShort();
+                if (opens_flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((opens_flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Opens.Modifier.SYNTHETIC);
+                    if ((opens_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.getModuleName(opens_to_index));
+                    }
+                    builder.opens(mods, pkg, targets);
+                } else {
+                    builder.opens(mods, pkg);
+                }
+            }
+        }
+
+        int uses_count = in.readUnsignedShort();
+        if (uses_count > 0) {
+            for (int i=0; i<uses_count; i++) {
+                int index = in.readUnsignedShort();
+                String sn = cpool.getClassName(index);
+                builder.uses(sn);
+            }
+        }
+
+        int provides_count = in.readUnsignedShort();
+        if (provides_count > 0) {
+            for (int i=0; i<provides_count; i++) {
+                int index = in.readUnsignedShort();
+                String sn = cpool.getClassName(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.getClassName(index);
+                    providers.add(pn);
+                }
+                builder.provides(sn, providers);
+            }
+        }
+
+        return builder;
+    }
+
+    /**
+     * Reads the ModulePackages attribute
+     */
+    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.getPackageName(index);
+            boolean added = packages.add(pn);
+            if (!added) {
+                throw invalidModuleDescriptor("Package " + pn + " in ModulePackages"
+                                              + "attribute more than once");
+            }
+        }
+        return packages;
+    }
+
+    /**
+     * Reads the ModuleMainClass attribute
+     */
+    private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int index = in.readUnsignedShort();
+        return cpool.getClassName(index);
+    }
+
+    /**
+     * Reads the ModuleTarget attribute
+     */
+    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        String[] values = new String[3];
+
+        int name_index = in.readUnsignedShort();
+        if (name_index != 0)
+            values[0] = cpool.getUtf8(name_index);
+
+        int arch_index = in.readUnsignedShort();
+        if (arch_index != 0)
+            values[1] = cpool.getUtf8(arch_index);
+
+        int version_index = in.readUnsignedShort();
+        if (version_index != 0)
+            values[2] = cpool.getUtf8(version_index);
+
+        return values;
+    }
+
+
+    /**
+     * Reads the ModuleHashes attribute
+     */
+    private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int algorithm_index = in.readUnsignedShort();
+        String algorithm = cpool.getUtf8(algorithm_index);
+
+        int hash_count = in.readUnsignedShort();
+        Map<String, byte[]> map = new HashMap<>(hash_count);
+        for (int i=0; i<hash_count; i++) {
+            int module_name_index = in.readUnsignedShort();
+            String mn = cpool.getModuleName(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);
+        }
+
+        return new ModuleHashes(algorithm, map);
+    }
+
+    /**
+     * Reads the ModuleResolution attribute.
+     */
+    private ModuleResolution readModuleResolution(DataInput in,
+                                                  ConstantPool cpool)
+        throws IOException
+    {
+        int flags = in.readUnsignedShort();
+
+        int reason = 0;
+        if ((flags & WARN_DEPRECATED) != 0)
+            reason = WARN_DEPRECATED;
+        if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0) {
+            if (reason != 0)
+                throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
+            reason = WARN_DEPRECATED_FOR_REMOVAL;
+        }
+        if ((flags & WARN_INCUBATING) != 0) {
+            if (reason != 0)
+                throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
+        }
+
+        return new ModuleResolution(flags);
+    }
+
+
+    /**
+     * Returns true if the given attribute can be present at most once
+     * in the class file. Returns false otherwise.
+     */
+    private static boolean isAttributeAtMostOnce(String name) {
+
+        if (name.equals(MODULE) ||
+                name.equals(SOURCE_FILE) ||
+                name.equals(SDE) ||
+                name.equals(MODULE_PACKAGES) ||
+                name.equals(MODULE_MAIN_CLASS) ||
+                name.equals(MODULE_TARGET) ||
+                name.equals(MODULE_HASHES) ||
+                name.equals(MODULE_RESOLUTION))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * 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, 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;
+        if (notAllowed == null) {
+            notAllowed = Set.of(
+                    "ConstantValue",
+                    "Code",
+                    "StackMapTable",
+                    "Exceptions",
+                    "EnclosingMethod",
+                    "Signature",
+                    "LineNumberTable",
+                    "LocalVariableTable",
+                    "LocalVariableTypeTable",
+                    "RuntimeVisibleParameterAnnotations",
+                    "RuntimeInvisibleParameterAnnotations",
+                    "RuntimeVisibleTypeAnnotations",
+                    "RuntimeInvisibleTypeAnnotations",
+                    "Synthetic",
+                    "AnnotationDefault",
+                    "BootstrapMethods",
+                    "MethodParameters");
+            predefinedNotAllowed = notAllowed;
+        }
+        return notAllowed.contains(name);
+    }
+
+    // lazily created set the pre-defined attributes that are not allowed
+    private static volatile Set<String> predefinedNotAllowed;
+
+
+    /**
+     * The constant pool in a class file.
+     */
+    private static class ConstantPool {
+        static final int CONSTANT_Utf8 = 1;
+        static final int CONSTANT_Integer = 3;
+        static final int CONSTANT_Float = 4;
+        static final int CONSTANT_Long = 5;
+        static final int CONSTANT_Double = 6;
+        static final int CONSTANT_Class = 7;
+        static final int CONSTANT_String = 8;
+        static final int CONSTANT_Fieldref = 9;
+        static final int CONSTANT_Methodref = 10;
+        static final int CONSTANT_InterfaceMethodref = 11;
+        static final int CONSTANT_NameAndType = 12;
+        static final int CONSTANT_MethodHandle = 15;
+        static final int CONSTANT_MethodType = 16;
+        static final int CONSTANT_InvokeDynamic = 18;
+        static final int CONSTANT_Module = 19;
+        static final int CONSTANT_Package = 20;
+
+        private static class Entry {
+            protected Entry(int tag) {
+                this.tag = tag;
+            }
+            final int tag;
+        }
+
+        private static class IndexEntry extends Entry {
+            IndexEntry(int tag, int index) {
+                super(tag);
+                this.index = index;
+            }
+            final int index;
+        }
+
+        private static class Index2Entry extends Entry {
+            Index2Entry(int tag, int index1, int index2) {
+                super(tag);
+                this.index1 = index1;
+                this.index2 = index2;
+            }
+            final int index1,  index2;
+        }
+
+        private static class ValueEntry extends Entry {
+            ValueEntry(int tag, Object value) {
+                super(tag);
+                this.value = value;
+            }
+            final Object value;
+        }
+
+        final Entry[] pool;
+
+        ConstantPool(DataInput in) throws IOException {
+            int count = in.readUnsignedShort();
+            pool = new Entry[count];
+
+            for (int i = 1; i < count; i++) {
+                int tag = in.readUnsignedByte();
+                switch (tag) {
+
+                    case CONSTANT_Utf8:
+                        String svalue = in.readUTF();
+                        pool[i] = new ValueEntry(tag, svalue);
+                        break;
+
+                    case CONSTANT_Class:
+                    case CONSTANT_Package:
+                    case CONSTANT_Module:
+                    case CONSTANT_String:
+                        int index = in.readUnsignedShort();
+                        pool[i] = new IndexEntry(tag, index);
+                        break;
+
+                    case CONSTANT_Double:
+                        double dvalue = in.readDouble();
+                        pool[i] = new ValueEntry(tag, dvalue);
+                        i++;
+                        break;
+
+                    case CONSTANT_Fieldref:
+                    case CONSTANT_InterfaceMethodref:
+                    case CONSTANT_Methodref:
+                    case CONSTANT_InvokeDynamic:
+                    case CONSTANT_NameAndType:
+                        int index1 = in.readUnsignedShort();
+                        int index2 = in.readUnsignedShort();
+                        pool[i] = new Index2Entry(tag, index1, index2);
+                        break;
+
+                    case CONSTANT_MethodHandle:
+                        int refKind = in.readUnsignedByte();
+                        index = in.readUnsignedShort();
+                        pool[i] = new Index2Entry(tag, refKind, index);
+                        break;
+
+                    case CONSTANT_MethodType:
+                        index = in.readUnsignedShort();
+                        pool[i] = new IndexEntry(tag, index);
+                        break;
+
+                    case CONSTANT_Float:
+                        float fvalue = in.readFloat();
+                        pool[i] = new ValueEntry(tag, fvalue);
+                        break;
+
+                    case CONSTANT_Integer:
+                        int ivalue = in.readInt();
+                        pool[i] = new ValueEntry(tag, ivalue);
+                        break;
+
+                    case CONSTANT_Long:
+                        long lvalue = in.readLong();
+                        pool[i] = new ValueEntry(tag, lvalue);
+                        i++;
+                        break;
+
+                    default:
+                        throw invalidModuleDescriptor("Bad constant pool entry: "
+                                                      + i);
+                }
+            }
+        }
+
+        String getClassName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Class) {
+                throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            checkUnqualifiedName("CONSTANT_Class", index, value);
+            return value.replace('/', '.');  // internal form -> binary name
+        }
+
+        String getPackageName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Package) {
+                throw invalidModuleDescriptor("CONSTANT_Package expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            checkUnqualifiedName("CONSTANT_Package", index, value);
+            return value.replace('/', '.');  // internal form -> binary name
+        }
+
+        String getModuleName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Module) {
+                throw invalidModuleDescriptor("CONSTANT_Module expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            return decodeModuleName(index, value);
+        }
+
+        String getUtf8(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Utf8) {
+                throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
+                                              + index);
+            }
+            return (String) (((ValueEntry) e).value);
+        }
+
+        void checkIndex(int index) {
+            if (index < 1 || index >= pool.length)
+                throw invalidModuleDescriptor("Index into constant pool out of range");
+        }
+
+        void checkUnqualifiedName(String what, int index, String value) {
+            int len = value.length();
+            if (len == 0) {
+                throw invalidModuleDescriptor(what + " at entry " + index
+                                              + " has zero length");
+            }
+            for (int i=0; i<len; i++) {
+                char c = value.charAt(i);
+                if (c == '.' || c == ';' || c == '[') {
+                    throw invalidModuleDescriptor(what + " at entry " + index
+                                                  + " has illegal character: '"
+                                                  + c + "'");
+                }
+            }
+        }
+
+        /**
+         * "Decode" a module name that has been read from the constant pool.
+         */
+        String decodeModuleName(int index, String value) {
+            int len = value.length();
+            if (len == 0) {
+                throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                              + index + " is zero length");
+            }
+            int i = 0;
+            while (i < len) {
+                int cp = value.codePointAt(i);
+                if (cp == ':' || cp == '@' || cp < 0x20) {
+                    throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                  + index + " has illegal character: "
+                                                  + Character.getName(cp));
+                }
+
+                // blackslash is the escape character
+                if (cp == '\\')
+                    return decodeModuleName(index, i, value);
+
+                i += Character.charCount(cp);
+            }
+            return value;
+        }
+
+        /**
+         * "Decode" a module name that has been read from the constant pool and
+         * partly checked for illegal characters (up to position {@code i}).
+         */
+        String decodeModuleName(int index, int i, String value) {
+            StringBuilder sb = new StringBuilder();
+
+            // copy the code points that have been checked
+            int j = 0;
+            while (j < i) {
+                int cp = value.codePointAt(j);
+                sb.appendCodePoint(cp);
+                j += Character.charCount(cp);
+            }
+
+            // decode from position {@code i} to end
+            int len = value.length();
+            while (i < len) {
+                int cp = value.codePointAt(i);
+                if (cp == ':' || cp == '@' || cp < 0x20) {
+                    throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                  + index + " has illegal character: "
+                                                  + Character.getName(cp));
+                }
+
+                // blackslash is the escape character
+                if (cp == '\\') {
+                    j = i + Character.charCount(cp);
+                    if (j >= len) {
+                        throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                       + index + " has illegal "
+                                                       + "escape sequence");
+                    }
+                    int next = value.codePointAt(j);
+                    if (next != '\\' && next != ':' && next != '@') {
+                        throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                      + index + " has illegal "
+                                                      + "escape sequence");
+                    }
+                    sb.appendCodePoint(next);
+                    i += Character.charCount(next);
+                } else {
+                    sb.appendCodePoint(cp);
+                }
+
+                i += Character.charCount(cp);
+            }
+            return sb.toString();
+        }
+    }
+
+    /**
+     * A DataInput implementation that reads from a ByteBuffer.
+     */
+    private static class DataInputWrapper implements DataInput {
+        private final ByteBuffer bb;
+
+        DataInputWrapper(ByteBuffer bb) {
+            this.bb = bb;
+        }
+
+        @Override
+        public void readFully(byte b[]) throws IOException {
+            readFully(b, 0, b.length);
+        }
+
+        @Override
+        public void readFully(byte b[], int off, int len) throws IOException {
+            try {
+                bb.get(b, off, len);
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int skipBytes(int n) {
+            int skip = Math.min(n, bb.remaining());
+            bb.position(bb.position() + skip);
+            return skip;
+        }
+
+        @Override
+        public boolean readBoolean() throws IOException {
+            try {
+                int ch = bb.get();
+                return (ch != 0);
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public byte readByte() throws IOException {