changeset 36512:1b1dea65af3e

Merge
author duke
date Wed, 05 Jul 2017 21:27:52 +0200
parents 9d0388c6b336 2d47f4ba3ddf
children 9fad97916314
files hotspot/src/jdk.vm.ci/share/classes/META-INF/services/jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java hotspot/test/compiler/jvmci/common/CompilerToVMHelper.java hotspot/test/compiler/jvmci/common/PublicMetaspaceWrapperObject.java hotspot/test/compiler/jvmci/events/MetaAccessWrapper.java hotspot/test/runtime/BadObjectClass/Object.java hotspot/test/testlibrary/jdk/test/lib/PerfCounter.java hotspot/test/testlibrary/jdk/test/lib/PerfCounters.java make/CheckModules.gmk make/GenerateModuleDeps.gmk modules.xml
diffstat 343 files changed, 19717 insertions(+), 5490 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags-top-repo	Thu Mar 17 19:04:16 2016 +0000
+++ b/.hgtags-top-repo	Wed Jul 05 21:27:52 2017 +0200
@@ -352,3 +352,4 @@
 4d65eba233a8730f913734a6804910b842d2cb54 jdk-9+107
 c7be2a78c31b3b6132f2f5e9e4b3d3bb1c20245c jdk-9+108
 1787bdaabb2b6f4193406e25a50cb0419ea8e8f3 jdk-9+109
+925be13b3740d07a5958ccb5ab3c0ae1baba7055 jdk-9+110
--- a/common/autoconf/basics.m4	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/basics.m4	Wed Jul 05 21:27:52 2017 +0200
@@ -843,6 +843,8 @@
   AC_CONFIG_FILES([$OUTPUT_ROOT/hotspot-spec.gmk:$AUTOCONF_DIR/hotspot-spec.gmk.in])
   # The bootcycle-spec.gmk file contains support for boot cycle builds.
   AC_CONFIG_FILES([$OUTPUT_ROOT/bootcycle-spec.gmk:$AUTOCONF_DIR/bootcycle-spec.gmk.in])
+  # The buildjdk-spec.gmk file contains support for building a buildjdk when cross compiling.
+  AC_CONFIG_FILES([$OUTPUT_ROOT/buildjdk-spec.gmk:$AUTOCONF_DIR/buildjdk-spec.gmk.in])
   # The compare.sh is used to compare the build output to other builds.
   AC_CONFIG_FILES([$OUTPUT_ROOT/compare.sh:$AUTOCONF_DIR/compare.sh.in])
   # The generated Makefile knows where the spec.gmk is and where the source is.
--- a/common/autoconf/boot-jdk.m4	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/boot-jdk.m4	Wed Jul 05 21:27:52 2017 +0200
@@ -304,6 +304,18 @@
   # When compiling code to be executed by the Boot JDK, force jdk8 compatibility.
   BOOT_JDK_SOURCETARGET="-source 8 -target 8"
   AC_SUBST(BOOT_JDK_SOURCETARGET)
+
+  ADD_JVM_ARG_IF_OK([-Xpatch:], dummy, [$JAVA])
+  AC_MSG_CHECKING([if Boot JDK supports modules])
+  if test "x$JVM_ARG_OK" = "xtrue"; then
+    AC_MSG_RESULT([yes])
+    BOOT_JDK_MODULAR="true"
+  else
+    AC_MSG_RESULT([no])
+    BOOT_JDK_MODULAR="false"
+  fi
+  AC_SUBST(BOOT_JDK_MODULAR)
+
   AC_SUBST(JAVAC_FLAGS)
 
   # Check if the boot jdk is 32 or 64 bit
@@ -397,3 +409,100 @@
   done
   AC_SUBST(JAVA_TOOL_FLAGS_SMALL)
 ])
+
+# BUILD_JDK: the location of the latest JDK that can run
+#   on the host system and supports the target class file version
+#   generated in this JDK build.  This variable should only be
+#   used after the launchers are built.
+#
+
+# Execute the check given as argument, and verify the result.
+# If the JDK was previously found, do nothing.
+# $1 A command line (typically autoconf macro) to execute
+AC_DEFUN([BOOTJDK_CHECK_BUILD_JDK],
+[
+  if test "x$BUILD_JDK_FOUND" = xno; then
+    # Execute the test
+    $1
+
+    # If previous step claimed to have found a JDK, check it to see if it seems to be valid.
+    if test "x$BUILD_JDK_FOUND" = xmaybe; then
+      # Do we have a bin/java?
+      if test ! -x "$BUILD_JDK/bin/java"; then
+        AC_MSG_NOTICE([Potential Build JDK found at $BUILD_JDK did not contain bin/java; ignoring])
+        BUILD_JDK_FOUND=no
+      elif test ! -x "$BUILD_JDK/bin/jlink"; then
+        AC_MSG_NOTICE([Potential Build JDK found at $BUILD_JDK did not contain bin/jlink; ignoring])
+        BUILD_JDK_FOUND=no
+      elif test ! -x "$BUILD_JDK/bin/javac"; then
+        # Do we have a bin/javac?
+        AC_MSG_NOTICE([Potential Build JDK found at $BUILD_JDK did not contain bin/javac; ignoring])
+        AC_MSG_NOTICE([(This might be a JRE instead of an JDK)])
+        BUILD_JDK_FOUND=no
+      else
+        # Oh, this is looking good! We probably have found a proper JDK. Is it the correct version?
+        BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | head -n 1`
+
+        # Extra M4 quote needed to protect [] in grep expression.
+        [FOUND_CORRECT_VERSION=`echo $BUILD_JDK_VERSION | grep  '\"1\.[9]\.'`]
+        if test "x$FOUND_CORRECT_VERSION" = x; then
+          AC_MSG_NOTICE([Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring])
+          AC_MSG_NOTICE([(Your Build JDK must be version 9)])
+          BUILD_JDK_FOUND=no
+        else
+          # We're done!
+          BUILD_JDK_FOUND=yes
+          BASIC_FIXUP_PATH(BUILD_JDK)
+          AC_MSG_CHECKING([for Build JDK])
+          AC_MSG_RESULT([$BUILD_JDK])
+          AC_MSG_CHECKING([Build JDK version])
+          BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | $TR '\n\r' '  '`
+          AC_MSG_RESULT([$BUILD_JDK_VERSION])
+        fi # end check jdk version
+      fi # end check java
+    fi # end check build jdk found
+  fi
+])
+
+# By default the BUILD_JDK is the JDK_OUTPUTDIR.  If the target architecture
+# is different than the host system doing the build (e.g. cross-compilation),
+# a special BUILD_JDK is built as part of the build process.  An external
+# prebuilt BUILD_JDK can also be supplied.
+AC_DEFUN([BOOTJDK_SETUP_BUILD_JDK],
+[
+  AC_ARG_WITH(build-jdk, [AS_HELP_STRING([--with-build-jdk],
+      [path to JDK of same version as is being built@<:@the newly built JDK@:>@])])
+
+  CREATE_BUILDJDK_FOR_HOST=false
+  BUILD_JDK_FOUND="no"
+  if test "x$with_build_jdk" != "x"; then
+    BOOTJDK_CHECK_BUILD_JDK([
+       if test "x$with_build_jdk" != x; then
+         BUILD_JDK=$with_build_jdk
+         BUILD_JDK_FOUND=maybe
+         AC_MSG_NOTICE([Found potential Build JDK using configure arguments])
+       fi])
+  else
+    if test "x$COMPILE_TYPE" = "xcross"; then
+      BUILD_JDK="\$(BUILDJDK_OUTPUTDIR)/jdk"
+      BUILD_JDK_FOUND=yes
+      CREATE_BUILDJDK=true
+      AC_MSG_CHECKING([for Build JDK])
+      AC_MSG_RESULT([yes, will build it for the host platform])
+    else
+      BUILD_JDK="\$(JDK_OUTPUTDIR)"
+      BUILD_JDK_FOUND=yes
+      AC_MSG_CHECKING([for Build JDK])
+      AC_MSG_RESULT([yes, will use output dir])
+    fi
+  fi
+
+  if test "x$BUILD_JDK_FOUND" != "xyes"; then
+    AC_MSG_CHECKING([for Build JDK])
+    AC_MSG_RESULT([no])
+    AC_MSG_ERROR([Could not find a suitable Build JDK])
+  fi
+
+  AC_SUBST(CREATE_BUILDJDK)
+  AC_SUBST(BUILD_JDK)
+])
--- a/common/autoconf/bootcycle-spec.gmk.in	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/bootcycle-spec.gmk.in	Wed Jul 05 21:27:52 2017 +0200
@@ -25,6 +25,8 @@
 
 # Support for building boot cycle builds
 
+BOOT_JDK_MODULAR := true
+
 # First include the real base spec.gmk file
 include @SPEC@
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/autoconf/buildjdk-spec.gmk.in	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,148 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# This spec file is used to compile a BUILD_JDK while cross compiling. The
+# BUILD_JDK runs on the build/host platform and is of the same version as
+# the main build.
+
+# First include the real base spec.gmk file
+include @SPEC@
+
+CC := @BUILD_CC@
+CXX := @BUILD_CXX@
+LD := @BUILD_LD@
+AS := @BUILD_AS@
+NM := @BUILD_NM@
+AR := @BUILD_AR@
+OBJCOPY := @BUILD_OBJCOPY@
+STRIP := @BUILD_STRIP@
+SYSROOT_CFLAGS := @BUILD_SYSROOT_CFLAGS@
+SYSROOT_LDFLAGS := @BUILD_SYSROOT_LDFLAGS@
+
+# These directories should not be moved to BUILDJDK_OUTPUTDIR
+HOTSPOT_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(HOTSPOT_OUTPUTDIR))
+HOTSPOT_DIST := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(HOTSPOT_DIST))
+SUPPORT_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(SUPPORT_OUTPUTDIR))
+JDK_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(JDK_OUTPUTDIR))
+
+OPENJDK_BUILD_CPU_LEGACY := @OPENJDK_BUILD_CPU_LEGACY@
+OPENJDK_BUILD_CPU_LEGACY_LIB := @OPENJDK_BUILD_CPU_LEGACY_LIB@
+OPENJDK_BUILD_CPU_LIBDIR := @OPENJDK_BUILD_CPU_LIBDIR@
+OPENJDK_TARGET_CPU_LIBDIR := @OPENJDK_BUILD_CPU_LIBDIR@
+OPENJDK_TARGET_CPU := @OPENJDK_BUILD_CPU@
+OPENJDK_TARGET_CPU_ARCH := @OPENJDK_BUILD_CPU_ARCH@
+OPENJDK_TARGET_CPU_BITS := @OPENJDK_BUILD_CPU_BITS@
+OPENJDK_TARGET_CPU_ENDIAN := @OPENJDK_BUILD_CPU_ENDIAN@
+OPENJDK_TARGET_CPU_LEGACY := @OPENJDK_BUILD_CPU_LEGACY@
+
+CFLAGS_JDKLIB := @OPENJDK_BUILD_CFLAGS_JDKLIB@
+CXXFLAGS_JDKLIB := @OPENJDK_BUILD_CXXFLAGS_JDKLIB@
+LDFLAGS_JDKLIB := @OPENJDK_BUILD_LDFLAGS_JDKLIB@
+CFLAGS_JDKEXE := @OPENJDK_BUILD_CFLAGS_JDKEXE@
+CXXFLAGS_JDKEXE := @OPENJDK_BUILD_CXXFLAGS_JDKEXE@
+LDFLAGS_JDKEXE := @OPENJDK_BUILD_LDFLAGS_JDKEXE@
+OPENJDK_TARGET_CPU_JLI_CFLAGS := @OPENJDK_BUILD_CPU_JLI_CFLAGS@
+
+# The compiler for the build platform is likely not warning compatible with the official
+# compiler.
+WARNINGS_AS_ERRORS := false
+DISABLE_WARNING_PREFIX := @BUILD_CC_DISABLE_WARNING_PREFIX@
+
+# Save speed and disk space by not enabling debug symbols for the buildjdk
+ENABLE_DEBUG_SYMBOLS := false
+
+####################################################
+#
+# Legacy Hotspot support
+
+# Legacy setting: OPT or DBG
+VARIANT := OPT
+# Legacy setting: true or false
+FASTDEBUG := false
+# Legacy setting: debugging the class files?
+DEBUG_CLASSFILES := false
+
+# Some users still set EXTRA_*FLAGS on the make command line. Must
+# make sure to override that when building buildjdk.
+override EXTRA_CFLAGS :=
+override EXTRA_CXXFLAGS :=
+override EXTRA_LDFLAGS :=
+
+# The HOSTCC/HOSTCXX is Hotspot terminology for the BUILD_CC/BUILD_CXX, i.e. the
+# compiler that produces code that can be run on the build platform.
+HOSTCC := $(BUILD_CC)
+HOSTCXX := $(BUILD_CXX)
+
+# Old name for OPENJDK_TARGET_OS (aix,bsd,hpux,linux,macosx,solaris,windows etc)
+PLATFORM := $(OPENJDK_BUILD_OS)
+# 32 or 64 bit
+ARCH_DATA_MODEL := $(OPENJDK_BUILD_CPU_BITS)
+
+ALT_BOOTDIR := $(BOOT_JDK)
+# Yet another name for arch used for an extra subdir below the jvm lib.
+# Uses i386 and amd64, instead of x86 and x86_64.
+LIBARCH := @OPENJDK_BUILD_CPU_LEGACY_LIB@
+# Set the cpu architecture. Some users still set ARCH on the make command line. Must
+# make sure to override that when building buildjdk.
+override ARCH := $(OPENJDK_BUILD_CPU_ARCH)
+# Legacy setting for building for a 64 bit machine.
+# If yes then this expands to _LP64 := 1
+ifeq ($(OPENJDK_BUILD_CPU_BITS), 64)
+  _LP64 := 1
+endif
+
+ALT_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)
+ALT_EXPORT_PATH := $(HOTSPOT_DIST)
+
+JVM_INTERPRETER := @JVM_INTERPRETER@
+ifeq ($(JVM_INTERPRETER), cpp)
+  CC_INTERP=true
+endif
+
+HOTSPOT_MAKE_ARGS := product docs export_product
+# Control wether Hotspot runs Queens test after building
+TEST_IN_BUILD := false
+
+USE_PRECOMPILED_HEADER := @USE_PRECOMPILED_HEADER@
+
+# Hotspot expects the variable FULL_DEBUG_SYMBOLS=1/0 to control debug symbols
+# creation.
+FULL_DEBUG_SYMBOLS := 0
+ZIP_DEBUGINFO_FILES := 0
+# Disable stripping
+STRIP_POLICY := none
+
+JVM_VARIANTS := server
+JVM_VARIANT_SERVER := true
+JVM_VARIANT_CLIENT := false
+JVM_VARIANT_MINIMAL1 := false
+JVM_VARIANT_KERNEL := false
+JVM_VARIANT_ZERO := false
+JVM_VARIANT_ZEROSHARK := false
+JVM_VARIANT_CORE := false
+
+# Sneak this in via the spec.gmk file, since we don't want to mess around too much with the Hotspot make files.
+# This is needed to get the LOG setting to work properly.
+include $(SRC_ROOT)/make/common/MakeBase.gmk
--- a/common/autoconf/configure.ac	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/configure.ac	Wed Jul 05 21:27:52 2017 +0200
@@ -134,6 +134,7 @@
 
 # We need build & target for this.
 JDKOPT_SETUP_JDK_OPTIONS
+JDKOPT_SETUP_JLINK_OPTIONS
 HOTSPOT_SETUP_HOTSPOT_OPTIONS
 JDKVER_SETUP_JDK_VERSION_NUMBERS
 
@@ -144,6 +145,7 @@
 ###############################################################################
 
 BOOTJDK_SETUP_BOOT_JDK
+BOOTJDK_SETUP_BUILD_JDK
 
 ###############################################################################
 #
@@ -155,6 +157,8 @@
 SRCDIRS_SETUP_ALTERNATIVE_TOPDIRS
 SRCDIRS_SETUP_OUTPUT_DIRS
 
+SRCDIRS_SETUP_IMPORT_MODULES
+
 ###############################################################################
 #
 # Setup the toolchain (compilers etc), i.e. tools used to compile and process
--- a/common/autoconf/flags.m4	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/flags.m4	Wed Jul 05 21:27:52 2017 +0200
@@ -689,9 +689,6 @@
       ;;
   esac
 
-  # Setup LP64
-  COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK $ADD_LP64"
-
   # Set some common defines. These works for all compilers, but assume
   # -D is universally accepted.
 
@@ -722,7 +719,12 @@
   COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D$OPENJDK_TARGET_OS_UPPERCASE"
 
   # Setup target CPU
-  COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY"
+  OPENJDK_TARGET_CCXXFLAGS_JDK="$OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $ADD_LP64 \
+      -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY"
+  OPENJDK_BUILD_CCXXFLAGS_JDK="$OPENJDK_BUILD_CCXXFLAGS_JDK \
+      $OPENJDK_BUILD_ADD_LP64 \
+      -DARCH='\"$OPENJDK_BUILD_CPU_LEGACY\"' -D$OPENJDK_BUILD_CPU_LEGACY"
 
   # Setup debug/release defines
   if test "x$DEBUG_LEVEL" = xrelease; then
@@ -766,17 +768,35 @@
       -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava"
 
   # The shared libraries are compiled using the picflag.
-  CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
-  CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA"
+  CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $CFLAGS_JDK $EXTRA_CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
+  CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA"
 
   # Executable flags
-  CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK"
-  CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK"
+  CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $CFLAGS_JDK $EXTRA_CFLAGS_JDK"
+  CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK"
+
+  # The corresponding flags for building for the build platform. This is still an
+  # approximation, we only need something that runs on this machine when cross
+  # compiling the product.
+  OPENJDK_BUILD_CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \
+      $PICFLAG $CFLAGS_JDKLIB_EXTRA"
+  OPENJDK_BUILD_CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \
+      $PICFLAG $CXXFLAGS_JDKLIB_EXTRA"
+  OPENJDK_BUILD_CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK"
+  OPENJDK_BUILD_CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK"
 
   AC_SUBST(CFLAGS_JDKLIB)
   AC_SUBST(CFLAGS_JDKEXE)
   AC_SUBST(CXXFLAGS_JDKLIB)
   AC_SUBST(CXXFLAGS_JDKEXE)
+  AC_SUBST(OPENJDK_BUILD_CFLAGS_JDKLIB)
+  AC_SUBST(OPENJDK_BUILD_CFLAGS_JDKEXE)
+  AC_SUBST(OPENJDK_BUILD_CXXFLAGS_JDKLIB)
+  AC_SUBST(OPENJDK_BUILD_CXXFLAGS_JDKEXE)
 
   # Flags for compiling test libraries
   CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
@@ -872,6 +892,9 @@
     LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined"
   fi
 
+  OPENJDK_BUILD_LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE}"
+  LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} ${EXTRA_LDFLAGS_JDK}"
+
   # Customize LDFLAGS for libs
   LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
 
@@ -882,30 +905,39 @@
     JDKLIB_LIBS=""
   else
     LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \
-        -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}"
+        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)"
 
     # On some platforms (mac) the linker warns about non existing -L dirs.
     # Add server first if available. Linking aginst client does not always produce the same results.
     # Only add client dir if client is being built. Add minimal (note not minimal1) if only building minimal1.
     # Default to server for other variants.
     if test "x$JVM_VARIANT_SERVER" = xtrue; then
-      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/server"
+      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
     elif test "x$JVM_VARIANT_CLIENT" = xtrue; then
-      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/client"
+      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/client"
     elif test "x$JVM_VARIANT_MINIMAL1" = xtrue; then
-      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/minimal"
+      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/minimal"
     else
-      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/server"
+      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
     fi
 
     JDKLIB_LIBS="-ljava -ljvm"
     if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
       JDKLIB_LIBS="$JDKLIB_LIBS -lc"
     fi
+
+    # When building a buildjdk, it's always only the server variant
+    OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \
+        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
   fi
 
+  OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_JDKLIB}"
+  LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${EXTRA_LDFLAGS_JDK}"
+
   AC_SUBST(LDFLAGS_JDKLIB)
   AC_SUBST(LDFLAGS_JDKEXE)
+  AC_SUBST(OPENJDK_BUILD_LDFLAGS_JDKLIB)
+  AC_SUBST(OPENJDK_BUILD_LDFLAGS_JDKEXE)
   AC_SUBST(JDKLIB_LIBS)
   AC_SUBST(JDKEXE_LIBS)
   AC_SUBST(LDFLAGS_CXX_JDK)
@@ -1075,5 +1107,6 @@
       ;;
   esac
   AC_SUBST(DISABLE_WARNING_PREFIX)
+  AC_SUBST(BUILD_CC_DISABLE_WARNING_PREFIX)
   AC_SUBST(CFLAGS_WARNINGS_ARE_ERRORS)
 ])
--- a/common/autoconf/generated-configure.sh	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/generated-configure.sh	Wed Jul 05 21:27:52 2017 +0200
@@ -694,6 +694,7 @@
 COPY_DEBUG_SYMBOLS
 COMPILE_WITH_DEBUG_SYMBOLS
 CFLAGS_WARNINGS_ARE_ERRORS
+BUILD_CC_DISABLE_WARNING_PREFIX
 DISABLE_WARNING_PREFIX
 HOTSPOT_SET_WARNINGS_AS_ERRORS
 WARNINGS_AS_ERRORS
@@ -705,12 +706,18 @@
 LDFLAGS_CXX_JDK
 JDKEXE_LIBS
 JDKLIB_LIBS
+OPENJDK_BUILD_LDFLAGS_JDKEXE
+OPENJDK_BUILD_LDFLAGS_JDKLIB
 LDFLAGS_JDKEXE
 LDFLAGS_JDKLIB
 CXXFLAGS_TESTEXE
 CXXFLAGS_TESTLIB
 CFLAGS_TESTEXE
 CFLAGS_TESTLIB
+OPENJDK_BUILD_CXXFLAGS_JDKEXE
+OPENJDK_BUILD_CXXFLAGS_JDKLIB
+OPENJDK_BUILD_CFLAGS_JDKEXE
+OPENJDK_BUILD_CFLAGS_JDKLIB
 CXXFLAGS_JDKEXE
 CXXFLAGS_JDKLIB
 CFLAGS_JDKEXE
@@ -759,6 +766,8 @@
 BUILD_AS
 BUILD_LDCXX
 BUILD_LD
+BUILD_STRIP
+BUILD_OBJCOPY
 BUILD_AR
 BUILD_NM
 BUILD_CXX
@@ -821,6 +830,12 @@
 LIBRARY_PREFIX
 TOOLCHAIN_TYPE
 STATIC_BUILD
+IMPORT_MODULES_MAKE
+IMPORT_MODULES_SRC
+IMPORT_MODULES_CONF
+IMPORT_MODULES_LIBS
+IMPORT_MODULES_CMDS
+IMPORT_MODULES_CLASSES
 BUILD_HOTSPOT
 HOTSPOT_DIST
 BUILD_OUTPUT
@@ -831,8 +846,11 @@
 JAXP_TOPDIR
 CORBA_TOPDIR
 LANGTOOLS_TOPDIR
+BUILD_JDK
+CREATE_BUILDJDK
 BOOT_JDK_BITS
 JAVAC_FLAGS
+BOOT_JDK_MODULAR
 BOOT_JDK_SOURCETARGET
 JARSIGNER
 JAR
@@ -862,6 +880,7 @@
 PRODUCT_NAME
 LAUNCHER_NAME
 TEST_IN_BUILD
+JLINK_KEEP_PACKAGED_MODULES
 COPYRIGHT_YEAR
 COMPRESS_JARS
 INCLUDE_SA
@@ -930,9 +949,13 @@
 DEFINE_CROSS_COMPILE_ARCH
 LP64
 OPENJDK_TARGET_OS_EXPORT_DIR
+OPENJDK_BUILD_CPU_JLI_CFLAGS
 OPENJDK_TARGET_CPU_JLI_CFLAGS
 OPENJDK_TARGET_CPU_OSARCH
 OPENJDK_TARGET_CPU_ISADIR
+OPENJDK_BUILD_CPU_LIBDIR
+OPENJDK_BUILD_CPU_LEGACY_LIB
+OPENJDK_BUILD_CPU_LEGACY
 OPENJDK_TARGET_CPU_LIBDIR
 OPENJDK_TARGET_CPU_LEGACY_LIB
 OPENJDK_TARGET_CPU_LEGACY
@@ -1080,6 +1103,7 @@
 with_cacerts_file
 enable_unlimited_crypto
 with_copyright_year
+enable_keep_packaged_modules
 enable_hotspot_test_in_build
 with_milestone
 with_update_version
@@ -1094,6 +1118,7 @@
 with_version_security
 with_version_patch
 with_boot_jdk
+with_build_jdk
 with_add_source_root
 with_override_source_root
 with_adds_and_overrides
@@ -1105,6 +1130,7 @@
 with_override_nashorn
 with_override_jdk
 with_import_hotspot
+with_import_modules
 enable_static_build
 with_toolchain_type
 with_extra_cflags
@@ -1248,6 +1274,8 @@
 BUILD_CXX
 BUILD_NM
 BUILD_AR
+BUILD_OBJCOPY
+BUILD_STRIP
 JTREGEXE
 XMKMF
 FREETYPE_CFLAGS
@@ -1890,6 +1918,8 @@
                           support) [enabled]
   --enable-unlimited-crypto
                           Enable unlimited crypto policy [disabled]
+  --disable-keep-packaged-modules
+                          Do not keep packaged modules in jdk image [enable]
   --enable-hotspot-test-in-build
                           run the Queens test after Hotspot build [disabled]
   --enable-static-build   enable static library build [disabled]
@@ -1973,6 +2003,8 @@
   --with-version-patch    Set version 'PATCH' field (fourth number) [not
                           specified]
   --with-boot-jdk         path to Boot JDK (used to bootstrap build) [probed]
+  --with-build-jdk        path to JDK of same version as is being built[the
+                          newly built JDK]
   --with-add-source-root  Deprecated. Option is kept for backwards
                           compatibility and is ignored
   --with-override-source-root
@@ -1999,6 +2031,8 @@
   --with-import-hotspot   import hotspot binaries from this jdk image or
                           hotspot build dist dir instead of building from
                           source
+  --with-import-modules   import a set of prebuilt modules either as a zip
+                          file or an exploded directory
   --with-toolchain-type   the toolchain type (or family) to use, use '--help'
                           to show possible values [platform dependent]
   --with-extra-cflags     extra flags to be used when compiling jdk c-files
@@ -2167,6 +2201,9 @@
   BUILD_CXX   Override default value for BUILD_CXX
   BUILD_NM    Override default value for BUILD_NM
   BUILD_AR    Override default value for BUILD_AR
+  BUILD_OBJCOPY
+              Override default value for BUILD_OBJCOPY
+  BUILD_STRIP Override default value for BUILD_STRIP
   JTREGEXE    Override default value for JTREGEXE
   XMKMF       Path to xmkmf, Makefile generator for X Window System
   FREETYPE_CFLAGS
@@ -3777,6 +3814,23 @@
 
 
 
+# BUILD_JDK: the location of the latest JDK that can run
+#   on the host system and supports the target class file version
+#   generated in this JDK build.  This variable should only be
+#   used after the launchers are built.
+#
+
+# Execute the check given as argument, and verify the result.
+# If the JDK was previously found, do nothing.
+# $1 A command line (typically autoconf macro) to execute
+
+
+# By default the BUILD_JDK is the JDK_OUTPUTDIR.  If the target architecture
+# is different than the host system doing the build (e.g. cross-compilation),
+# a special BUILD_JDK is built as part of the build process.  An external
+# prebuilt BUILD_JDK can also be supplied.
+
+
 #
 # Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4192,6 +4246,13 @@
 #
 
 
+################################################################################
+#
+# jlink options.
+# We always keep packaged modules in JDK image.
+#
+
+
 #
 # Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4628,6 +4689,12 @@
 
 
 
+################################################################################
+# Define a mechanism for importing extra prebuilt modules
+#
+
+
+
 #
 # Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4862,7 +4929,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1457684806
+DATE_WHEN_GENERATED=1458008154
 
 ###############################################################################
 #
@@ -15157,6 +15224,37 @@
   fi
 
 
+  # Now do the same for OPENJDK_BUILD_CPU...
+  # Also store the legacy naming of the cpu.
+  # Ie i586 and amd64 instead of x86 and x86_64
+  OPENJDK_BUILD_CPU_LEGACY="$OPENJDK_BUILD_CPU"
+  if test "x$OPENJDK_BUILD_CPU" = xx86; then
+    OPENJDK_BUILD_CPU_LEGACY="i586"
+  elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then
+    # On all platforms except MacOSX replace x86_64 with amd64.
+    OPENJDK_BUILD_CPU_LEGACY="amd64"
+  fi
+
+
+  # And the second legacy naming of the cpu.
+  # Ie i386 and amd64 instead of x86 and x86_64.
+  OPENJDK_BUILD_CPU_LEGACY_LIB="$OPENJDK_BUILD_CPU"
+  if test "x$OPENJDK_BUILD_CPU" = xx86; then
+    OPENJDK_BUILD_CPU_LEGACY_LIB="i386"
+  elif test "x$OPENJDK_BUILD_CPU" = xx86_64; then
+    OPENJDK_BUILD_CPU_LEGACY_LIB="amd64"
+  fi
+
+
+  # This is the name of the cpu (but using i386 and amd64 instead of
+  # x86 and x86_64, respectively), preceeded by a /, to be used when
+  # locating libraries. On macosx, it's empty, though.
+  OPENJDK_BUILD_CPU_LIBDIR="/$OPENJDK_BUILD_CPU_LEGACY_LIB"
+  if test "x$OPENJDK_BUILD_OS" = xmacosx; then
+    OPENJDK_BUILD_CPU_LIBDIR=""
+  fi
+
+
   # OPENJDK_TARGET_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to
   # /amd64 or /sparcv9. This string is appended to some library paths, like this:
   # /usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libexample.so
@@ -15199,6 +15297,24 @@
   fi
 
 
+  OPENJDK_BUILD_CPU_JLI="$OPENJDK_BUILD_CPU"
+  if test "x$OPENJDK_BUILD_CPU" = xx86; then
+    OPENJDK_BUILD_CPU_JLI="i386"
+  elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then
+    # On all platforms except macosx, we replace x86_64 with amd64.
+    OPENJDK_BUILD_CPU_JLI="amd64"
+  fi
+  # Now setup the -D flags for building libjli.
+  OPENJDK_BUILD_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_BUILD_CPU_JLI\"'"
+  if test "x$OPENJDK_BUILD_OS" = xsolaris; then
+    if test "x$OPENJDK_BUILD_CPU_ARCH" = xsparc; then
+      OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'"
+    elif test "x$OPENJDK_BUILD_CPU_ARCH" = xx86; then
+      OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'"
+    fi
+  fi
+
+
   if test "x$OPENJDK_TARGET_OS" = xmacosx; then
       OPENJDK_TARGET_OS_EXPORT_DIR=macosx
   else
@@ -15216,6 +15332,11 @@
   fi
   LP64=$A_LP64
 
+  if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then
+    if test "x$OPENJDK_BUILD_OS" = xlinux || test "x$OPENJDK_BUILD_OS" = xmacosx; then
+      OPENJDK_BUILD_ADD_LP64="-D_LP64=1"
+    fi
+  fi
 
   if test "x$COMPILE_TYPE" = "xcross"; then
     # FIXME: ... or should this include reduced builds..?
@@ -16701,6 +16822,9 @@
   # The bootcycle-spec.gmk file contains support for boot cycle builds.
   ac_config_files="$ac_config_files $OUTPUT_ROOT/bootcycle-spec.gmk:$AUTOCONF_DIR/bootcycle-spec.gmk.in"
 
+  # The buildjdk-spec.gmk file contains support for building a buildjdk when cross compiling.
+  ac_config_files="$ac_config_files $OUTPUT_ROOT/buildjdk-spec.gmk:$AUTOCONF_DIR/buildjdk-spec.gmk.in"
+
   # The compare.sh is used to compare the build output to other builds.
   ac_config_files="$ac_config_files $OUTPUT_ROOT/compare.sh:$AUTOCONF_DIR/compare.sh.in"
 
@@ -23299,6 +23423,35 @@
 
 
 
+  # Check whether --enable-keep-packaged-modules was given.
+if test "${enable_keep_packaged_modules+set}" = set; then :
+  enableval=$enable_keep_packaged_modules;
+fi
+
+
+  if test "x$enable_keep_packaged_modules" = "xyes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if packaged modules are kept" >&5
+$as_echo_n "checking if packaged modules are kept... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    JLINK_KEEP_PACKAGED_MODULES=true
+  elif test "x$enable_keep_packaged_modules" = "xno"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if packaged modules are kept" >&5
+$as_echo_n "checking if packaged modules are kept... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    JLINK_KEEP_PACKAGED_MODULES=false
+  elif test "x$enable_keep_packaged_modules" = "x"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5
+$as_echo "yes (default)" >&6; }
+    JLINK_KEEP_PACKAGED_MODULES=true
+  else
+    as_fn_error $? "--enable-keep-packaged-modules accepts no argument" "$LINENO" 5
+  fi
+
+
+
+
   # Control wether Hotspot runs Queens test after build.
   # Check whether --enable-hotspot-test-in-build was given.
 if test "${enable_hotspot_test_in_build+set}" = set; then :
@@ -29596,6 +29749,35 @@
 
 
 
+  $ECHO "Check if jvm arg is ok: -Xpatch:" >&5
+  $ECHO "Command: $JAVA -Xpatch: -version" >&5
+  OUTPUT=`$JAVA -Xpatch: -version 2>&1`
+  FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
+  FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
+  if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+    dummy="$dummy -Xpatch:"
+    JVM_ARG_OK=true
+  else
+    $ECHO "Arg failed:" >&5
+    $ECHO "$OUTPUT" >&5
+    JVM_ARG_OK=false
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Boot JDK supports modules" >&5
+$as_echo_n "checking if Boot JDK supports modules... " >&6; }
+  if test "x$JVM_ARG_OK" = "xtrue"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    BOOT_JDK_MODULAR="true"
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    BOOT_JDK_MODULAR="false"
+  fi
+
+
+
+
   # Check if the boot jdk is 32 or 64 bit
   if "$JAVA" -d64 -version > /dev/null 2>&1; then
     BOOT_JDK_BITS="64"
@@ -29609,6 +29791,237 @@
 
 
 
+
+# Check whether --with-build-jdk was given.
+if test "${with_build_jdk+set}" = set; then :
+  withval=$with_build_jdk;
+fi
+
+
+  CREATE_BUILDJDK_FOR_HOST=false
+  BUILD_JDK_FOUND="no"
+  if test "x$with_build_jdk" != "x"; then
+
+  if test "x$BUILD_JDK_FOUND" = xno; then
+    # Execute the test
+
+       if test "x$with_build_jdk" != x; then
+         BUILD_JDK=$with_build_jdk
+         BUILD_JDK_FOUND=maybe
+         { $as_echo "$as_me:${as_lineno-$LINENO}: Found potential Build JDK using configure arguments" >&5
+$as_echo "$as_me: Found potential Build JDK using configure arguments" >&6;}
+       fi
+
+    # If previous step claimed to have found a JDK, check it to see if it seems to be valid.
+    if test "x$BUILD_JDK_FOUND" = xmaybe; then
+      # Do we have a bin/java?
+      if test ! -x "$BUILD_JDK/bin/java"; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Build JDK found at $BUILD_JDK did not contain bin/java; ignoring" >&5
+$as_echo "$as_me: Potential Build JDK found at $BUILD_JDK did not contain bin/java; ignoring" >&6;}
+        BUILD_JDK_FOUND=no
+      elif test ! -x "$BUILD_JDK/bin/jlink"; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Build JDK found at $BUILD_JDK did not contain bin/jlink; ignoring" >&5
+$as_echo "$as_me: Potential Build JDK found at $BUILD_JDK did not contain bin/jlink; ignoring" >&6;}
+        BUILD_JDK_FOUND=no
+      elif test ! -x "$BUILD_JDK/bin/javac"; then
+        # Do we have a bin/javac?
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Build JDK found at $BUILD_JDK did not contain bin/javac; ignoring" >&5
+$as_echo "$as_me: Potential Build JDK found at $BUILD_JDK did not contain bin/javac; ignoring" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: (This might be a JRE instead of an JDK)" >&5
+$as_echo "$as_me: (This might be a JRE instead of an JDK)" >&6;}
+        BUILD_JDK_FOUND=no
+      else
+        # Oh, this is looking good! We probably have found a proper JDK. Is it the correct version?
+        BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | head -n 1`
+
+        # Extra M4 quote needed to protect [] in grep expression.
+        FOUND_CORRECT_VERSION=`echo $BUILD_JDK_VERSION | grep  '\"1\.[9]\.'`
+        if test "x$FOUND_CORRECT_VERSION" = x; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring" >&5
+$as_echo "$as_me: Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring" >&6;}
+          { $as_echo "$as_me:${as_lineno-$LINENO}: (Your Build JDK must be version 9)" >&5
+$as_echo "$as_me: (Your Build JDK must be version 9)" >&6;}
+          BUILD_JDK_FOUND=no
+        else
+          # We're done!
+          BUILD_JDK_FOUND=yes
+
+  # Only process if variable expands to non-empty
+
+  if test "x$BUILD_JDK" != x; then
+    if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  path="$BUILD_JDK"
+  new_path=`$CYGPATH -u "$path"`
+
+  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+  # "foo.exe" is OK but "foo" is an error.
+  #
+  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # It is also a way to make sure we got the proper file name for the real test later on.
+  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+  if test "x$test_shortpath" = x; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_JDK, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of BUILD_JDK, which resolves as \"$path\", is invalid." >&6;}
+    as_fn_error $? "Cannot locate the the path of BUILD_JDK" "$LINENO" 5
+  fi
+
+  # Call helper function which possibly converts this using DOS-style short mode.
+  # If so, the updated path is stored in $new_path.
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+      # Going to short mode and back again did indeed matter. Since short mode is
+      # case insensitive, let's make it lowercase to improve readability.
+      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+      # Now convert it back to Unix-style (cygpath)
+      input_path=`$CYGPATH -u "$shortmode_path"`
+      new_path="$input_path"
+    fi
+  fi
+
+  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+  if test "x$test_cygdrive_prefix" = x; then
+    # As a simple fix, exclude /usr/bin since it's not a real path.
+    if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+      # a path prefixed by /cygdrive for fixpath to work.
+      new_path="$CYGWIN_ROOT_PATH$input_path"
+    fi
+  fi
+
+
+  if test "x$path" != "x$new_path"; then
+    BUILD_JDK="$new_path"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting BUILD_JDK to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting BUILD_JDK to \"$new_path\"" >&6;}
+  fi
+
+    elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+  path="$BUILD_JDK"
+  has_colon=`$ECHO $path | $GREP ^.:`
+  new_path="$path"
+  if test "x$has_colon" = x; then
+    # Not in mixed or Windows style, start by that.
+    new_path=`cmd //c echo $path`
+  fi
+
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+  fi
+
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+  if test "x$path" != "x$new_path"; then
+    BUILD_JDK="$new_path"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting BUILD_JDK to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting BUILD_JDK to \"$new_path\"" >&6;}
+  fi
+
+  # Save the first 10 bytes of this path to the storage, so fixpath can work.
+  all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+    else
+      # We're on a unix platform. Hooray! :)
+      path="$BUILD_JDK"
+      has_space=`$ECHO "$path" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_JDK, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of BUILD_JDK, which resolves as \"$path\", is invalid." >&6;}
+        as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+      fi
+
+      # Use eval to expand a potential ~
+      eval path="$path"
+      if test ! -f "$path" && test ! -d "$path"; then
+        as_fn_error $? "The path of BUILD_JDK, which resolves as \"$path\", is not found." "$LINENO" 5
+      fi
+
+      if test -d "$path"; then
+        BUILD_JDK="`cd "$path"; $THEPWDCMD -L`"
+      else
+        dir="`$DIRNAME "$path"`"
+        base="`$BASENAME "$path"`"
+        BUILD_JDK="`cd "$dir"; $THEPWDCMD -L`/$base"
+      fi
+    fi
+  fi
+
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Build JDK" >&5
+$as_echo_n "checking for Build JDK... " >&6; }
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_JDK" >&5
+$as_echo "$BUILD_JDK" >&6; }
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking Build JDK version" >&5
+$as_echo_n "checking Build JDK version... " >&6; }
+          BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | $TR '\n\r' '  '`
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_JDK_VERSION" >&5
+$as_echo "$BUILD_JDK_VERSION" >&6; }
+        fi # end check jdk version
+      fi # end check java
+    fi # end check build jdk found
+  fi
+
+  else
+    if test "x$COMPILE_TYPE" = "xcross"; then
+      BUILD_JDK="\$(BUILDJDK_OUTPUTDIR)/jdk"
+      BUILD_JDK_FOUND=yes
+      CREATE_BUILDJDK=true
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Build JDK" >&5
+$as_echo_n "checking for Build JDK... " >&6; }
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, will build it for the host platform" >&5
+$as_echo "yes, will build it for the host platform" >&6; }
+    else
+      BUILD_JDK="\$(JDK_OUTPUTDIR)"
+      BUILD_JDK_FOUND=yes
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Build JDK" >&5
+$as_echo_n "checking for Build JDK... " >&6; }
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, will use output dir" >&5
+$as_echo "yes, will use output dir" >&6; }
+    fi
+  fi
+
+  if test "x$BUILD_JDK_FOUND" != "xyes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Build JDK" >&5
+$as_echo_n "checking for Build JDK... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    as_fn_error $? "Could not find a suitable Build JDK" "$LINENO" 5
+  fi
+
+
+
+
+
 ###############################################################################
 #
 # Configure the sources to use. We can add or override individual directories.
@@ -29758,6 +30171,189 @@
   JDK_OUTPUTDIR="$OUTPUT_ROOT/jdk"
 
 
+
+
+# Check whether --with-import-modules was given.
+if test "${with_import_modules+set}" = set; then :
+  withval=$with_import_modules;
+fi
+
+
+  if test "x$with_import_modules" != x \
+      && test "x$with_import_modules" != "xno"; then
+    if test -d "$with_import_modules"; then
+      IMPORT_MODULES_TOPDIR="$with_import_modules"
+
+  # Only process if variable expands to non-empty
+
+  if test "x$IMPORT_MODULES_TOPDIR" != x; then
+    if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  path="$IMPORT_MODULES_TOPDIR"
+  new_path=`$CYGPATH -u "$path"`
+
+  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+  # "foo.exe" is OK but "foo" is an error.
+  #
+  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # It is also a way to make sure we got the proper file name for the real test later on.
+  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+  if test "x$test_shortpath" = x; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is invalid." >&6;}
+    as_fn_error $? "Cannot locate the the path of IMPORT_MODULES_TOPDIR" "$LINENO" 5
+  fi
+
+  # Call helper function which possibly converts this using DOS-style short mode.
+  # If so, the updated path is stored in $new_path.
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+      # Going to short mode and back again did indeed matter. Since short mode is
+      # case insensitive, let's make it lowercase to improve readability.
+      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+      # Now convert it back to Unix-style (cygpath)
+      input_path=`$CYGPATH -u "$shortmode_path"`
+      new_path="$input_path"
+    fi
+  fi
+
+  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+  if test "x$test_cygdrive_prefix" = x; then
+    # As a simple fix, exclude /usr/bin since it's not a real path.
+    if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+      # a path prefixed by /cygdrive for fixpath to work.
+      new_path="$CYGWIN_ROOT_PATH$input_path"
+    fi
+  fi
+
+
+  if test "x$path" != "x$new_path"; then
+    IMPORT_MODULES_TOPDIR="$new_path"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting IMPORT_MODULES_TOPDIR to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting IMPORT_MODULES_TOPDIR to \"$new_path\"" >&6;}
+  fi
+
+    elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+  path="$IMPORT_MODULES_TOPDIR"
+  has_colon=`$ECHO $path | $GREP ^.:`
+  new_path="$path"
+  if test "x$has_colon" = x; then
+    # Not in mixed or Windows style, start by that.
+    new_path=`cmd //c echo $path`
+  fi
+
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+  fi
+
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+  if test "x$path" != "x$new_path"; then
+    IMPORT_MODULES_TOPDIR="$new_path"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting IMPORT_MODULES_TOPDIR to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting IMPORT_MODULES_TOPDIR to \"$new_path\"" >&6;}
+  fi
+
+  # Save the first 10 bytes of this path to the storage, so fixpath can work.
+  all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+    else
+      # We're on a unix platform. Hooray! :)
+      path="$IMPORT_MODULES_TOPDIR"
+      has_space=`$ECHO "$path" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is invalid." >&6;}
+        as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+      fi
+
+      # Use eval to expand a potential ~
+      eval path="$path"
+      if test ! -f "$path" && test ! -d "$path"; then
+        as_fn_error $? "The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is not found." "$LINENO" 5
+      fi
+
+      if test -d "$path"; then
+        IMPORT_MODULES_TOPDIR="`cd "$path"; $THEPWDCMD -L`"
+      else
+        dir="`$DIRNAME "$path"`"
+        base="`$BASENAME "$path"`"
+        IMPORT_MODULES_TOPDIR="`cd "$dir"; $THEPWDCMD -L`/$base"
+      fi
+    fi
+  fi
+
+    elif test -e "$with_import_modules"; then
+      IMPORT_MODULES_TOPDIR="$CONFIGURESUPPORT_OUTPUTDIR/import-modules"
+      $RM -rf "$IMPORT_MODULES_TOPDIR"
+      $MKDIR -p "$IMPORT_MODULES_TOPDIR"
+      if ! $UNZIP -q "$with_import_modules" -d "$IMPORT_MODULES_TOPDIR"; then
+        as_fn_error $? "--with-import-modules=\"$with_import_modules\" must point to a dir or a zip file" "$LINENO" 5
+      fi
+    else
+      as_fn_error $? "--with-import-modules=\"$with_import_modules\" must point to a dir or a zip file" "$LINENO" 5
+    fi
+  fi
+
+  if test -d "$IMPORT_MODULES_TOPDIR/modules"; then
+    IMPORT_MODULES_CLASSES="$IMPORT_MODULES_TOPDIR/modules"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_cmds"; then
+    IMPORT_MODULES_CMDS="$IMPORT_MODULES_TOPDIR/modules_cmds"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_libs"; then
+    IMPORT_MODULES_LIBS="$IMPORT_MODULES_TOPDIR/modules_libs"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_conf"; then
+    IMPORT_MODULES_CONF="$IMPORT_MODULES_TOPDIR/modules_conf"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then
+    IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/make"; then
+    IMPORT_MODULES_MAKE="$IMPORT_MODULES_TOPDIR/make"
+  fi
+
+
+
+
+
+
+
+
+
 ###############################################################################
 #
 # Setup the toolchain (compilers etc), i.e. tools used to compile and process
@@ -44514,6 +45110,972 @@
     fi
   fi
 
+
+
+  # Publish this variable in the help.
+
+
+  if [ -z "${BUILD_OBJCOPY+x}" ]; then
+    # The variable is not set by user, try to locate tool using the code snippet
+    for ac_prog in objcopy
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_BUILD_OBJCOPY+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $BUILD_OBJCOPY in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_BUILD_OBJCOPY="$BUILD_OBJCOPY" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_BUILD_OBJCOPY="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+BUILD_OBJCOPY=$ac_cv_path_BUILD_OBJCOPY
+if test -n "$BUILD_OBJCOPY"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_OBJCOPY" >&5
+$as_echo "$BUILD_OBJCOPY" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$BUILD_OBJCOPY" && break
+done
+
+  else
+    # The variable is set, but is it from the command line or the environment?
+
+    # Try to remove the string !BUILD_OBJCOPY! from our list.
+    try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!BUILD_OBJCOPY!/}
+    if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then
+      # If it failed, the variable was not from the command line. Ignore it,
+      # but warn the user (except for BASH, which is always set by the calling BASH).
+      if test "xBUILD_OBJCOPY" != xBASH; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of BUILD_OBJCOPY from the environment. Use command line variables instead." >&5
+$as_echo "$as_me: WARNING: Ignoring value of BUILD_OBJCOPY from the environment. Use command line variables instead." >&2;}
+      fi
+      # Try to locate tool using the code snippet
+      for ac_prog in objcopy
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_BUILD_OBJCOPY+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $BUILD_OBJCOPY in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_BUILD_OBJCOPY="$BUILD_OBJCOPY" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_BUILD_OBJCOPY="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+BUILD_OBJCOPY=$ac_cv_path_BUILD_OBJCOPY
+if test -n "$BUILD_OBJCOPY"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_OBJCOPY" >&5
+$as_echo "$BUILD_OBJCOPY" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$BUILD_OBJCOPY" && break
+done
+
+    else
+      # If it succeeded, then it was overridden by the user. We will use it
+      # for the tool.
+
+      # First remove it from the list of overridden variables, so we can test
+      # for unknown variables in the end.
+      CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var"
+
+      # Check if we try to supply an empty value
+      if test "x$BUILD_OBJCOPY" = x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool BUILD_OBJCOPY= (no value)" >&5
+$as_echo "$as_me: Setting user supplied tool BUILD_OBJCOPY= (no value)" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILD_OBJCOPY" >&5
+$as_echo_n "checking for BUILD_OBJCOPY... " >&6; }
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
+$as_echo "disabled" >&6; }
+      else
+        # Check if the provided tool contains a complete path.
+        tool_specified="$BUILD_OBJCOPY"
+        tool_basename="${tool_specified##*/}"
+        if test "x$tool_basename" = "x$tool_specified"; then
+          # A command without a complete path is provided, search $PATH.
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool BUILD_OBJCOPY=$tool_basename" >&5
+$as_echo "$as_me: Will search for user supplied tool BUILD_OBJCOPY=$tool_basename" >&6;}
+          # Extract the first word of "$tool_basename", so it can be a program name with args.
+set dummy $tool_basename; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_BUILD_OBJCOPY+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $BUILD_OBJCOPY in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_BUILD_OBJCOPY="$BUILD_OBJCOPY" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_BUILD_OBJCOPY="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+BUILD_OBJCOPY=$ac_cv_path_BUILD_OBJCOPY
+if test -n "$BUILD_OBJCOPY"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_OBJCOPY" >&5
+$as_echo "$BUILD_OBJCOPY" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+          if test "x$BUILD_OBJCOPY" = x; then
+            as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5
+          fi
+        else
+          # Otherwise we believe it is a complete path. Use it as it is.
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool BUILD_OBJCOPY=$tool_specified" >&5
+$as_echo "$as_me: Will use user supplied tool BUILD_OBJCOPY=$tool_specified" >&6;}
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILD_OBJCOPY" >&5
+$as_echo_n "checking for BUILD_OBJCOPY... " >&6; }
+          if test ! -x "$tool_specified"; then
+            { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+            as_fn_error $? "User supplied tool BUILD_OBJCOPY=$tool_specified does not exist or is not executable" "$LINENO" 5
+          fi
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5
+$as_echo "$tool_specified" >&6; }
+        fi
+      fi
+    fi
+
+  fi
+
+
+
+  # Only process if variable expands to non-empty
+
+  if test "x$BUILD_OBJCOPY" != x; then
+    if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+  # First separate the path from the arguments. This will split at the first
+  # space.
+  complete="$BUILD_OBJCOPY"
+  path="${complete%% *}"
+  tmp="$complete EOL"
+  arguments="${tmp#* }"
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  new_path=`$CYGPATH -u "$path"`
+
+  # Now try to locate executable using which
+  new_path=`$WHICH "$new_path" 2> /dev/null`
+  # bat and cmd files are not always considered executable in cygwin causing which
+  # to not find them
+  if test "x$new_path" = x \
+      && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+      && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+    new_path=`$CYGPATH -u "$path"`
+  fi
+  if test "x$new_path" = x; then
+    # Oops. Which didn't find the executable.
+    # The splitting of arguments from the executable at a space might have been incorrect,
+    # since paths with space are more likely in Windows. Give it another try with the whole
+    # argument.
+    path="$complete"
+    arguments="EOL"
+    new_path=`$CYGPATH -u "$path"`
+    new_path=`$WHICH "$new_path" 2> /dev/null`
+    # bat and cmd files are not always considered executable in cygwin causing which
+    # to not find them
+    if test "x$new_path" = x \
+        && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+        && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+      new_path=`$CYGPATH -u "$path"`
+    fi
+    if test "x$new_path" = x; then
+      # It's still not found. Now this is an unrecoverable error.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&6;}
+      has_space=`$ECHO "$complete" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5
+$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;}
+      fi
+      as_fn_error $? "Cannot locate the the path of BUILD_OBJCOPY" "$LINENO" 5
+    fi
+  fi
+
+  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+  # "foo.exe" is OK but "foo" is an error.
+  #
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
+  # It is also a way to make sure we got the proper file name for the real test later on.
+  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+  if test "x$test_shortpath" = x; then
+    # Short path failed, file does not exist as specified.
+    # Try adding .exe or .cmd
+    if test -f "${new_path}.exe"; then
+      input_to_shortpath="${new_path}.exe"
+    elif test -f "${new_path}.cmd"; then
+      input_to_shortpath="${new_path}.cmd"
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_OBJCOPY, which resolves as \"$new_path\", is invalid." >&5
+$as_echo "$as_me: The path of BUILD_OBJCOPY, which resolves as \"$new_path\", is invalid." >&6;}
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&5
+$as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&6;}
+      as_fn_error $? "Cannot locate the the path of BUILD_OBJCOPY" "$LINENO" 5
+    fi
+  else
+    input_to_shortpath="$new_path"
+  fi
+
+  # Call helper function which possibly converts this using DOS-style short mode.
+  # If so, the updated path is stored in $new_path.
+  new_path="$input_to_shortpath"
+
+  input_path="$input_to_shortpath"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+      # Going to short mode and back again did indeed matter. Since short mode is
+      # case insensitive, let's make it lowercase to improve readability.
+      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+      # Now convert it back to Unix-style (cygpath)
+      input_path=`$CYGPATH -u "$shortmode_path"`
+      new_path="$input_path"
+    fi
+  fi
+
+  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+  if test "x$test_cygdrive_prefix" = x; then
+    # As a simple fix, exclude /usr/bin since it's not a real path.
+    if test "x`$ECHO $input_to_shortpath | $GREP ^/usr/bin/`" = x; then
+      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+      # a path prefixed by /cygdrive for fixpath to work.
+      new_path="$CYGWIN_ROOT_PATH$input_path"
+    fi
+  fi
+
+  # remove trailing .exe if any
+  new_path="${new_path/%.exe/}"
+
+    elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+  # First separate the path from the arguments. This will split at the first
+  # space.
+  complete="$BUILD_OBJCOPY"
+  path="${complete%% *}"
+  tmp="$complete EOL"
+  arguments="${tmp#* }"
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+
+  # Now try to locate executable using which
+  new_path=`$WHICH "$new_path" 2> /dev/null`
+
+  if test "x$new_path" = x; then
+    # Oops. Which didn't find the executable.
+    # The splitting of arguments from the executable at a space might have been incorrect,
+    # since paths with space are more likely in Windows. Give it another try with the whole
+    # argument.
+    path="$complete"
+    arguments="EOL"
+    new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+
+    new_path=`$WHICH "$new_path" 2> /dev/null`
+    # bat and cmd files are not always considered executable in MSYS causing which
+    # to not find them
+    if test "x$new_path" = x \
+        && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+        && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+      new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+    fi
+
+    if test "x$new_path" = x; then
+      # It's still not found. Now this is an unrecoverable error.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&6;}
+      has_space=`$ECHO "$complete" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5
+$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;}
+      fi
+      as_fn_error $? "Cannot locate the the path of BUILD_OBJCOPY" "$LINENO" 5
+    fi
+  fi
+
+  # Now new_path has a complete unix path to the binary
+  if test "x`$ECHO $new_path | $GREP ^/bin/`" != x; then
+    # Keep paths in /bin as-is, but remove trailing .exe if any
+    new_path="${new_path/%.exe/}"
+    # Do not save /bin paths to all_fixpath_prefixes!
+  else
+    # Not in mixed or Windows style, start by that.
+    new_path=`cmd //c echo $new_path`
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+  fi
+
+    # Output is in $new_path
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+    # remove trailing .exe if any
+    new_path="${new_path/%.exe/}"
+
+    # Save the first 10 bytes of this path to the storage, so fixpath can work.
+    all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+  fi
+
+    else
+      # We're on a unix platform. Hooray! :)
+      # First separate the path from the arguments. This will split at the first
+      # space.
+      complete="$BUILD_OBJCOPY"
+      path="${complete%% *}"
+      tmp="$complete EOL"
+      arguments="${tmp#* }"
+
+      # Cannot rely on the command "which" here since it doesn't always work.
+      is_absolute_path=`$ECHO "$path" | $GREP ^/`
+      if test -z "$is_absolute_path"; then
+        # Path to executable is not absolute. Find it.
+        IFS_save="$IFS"
+        IFS=:
+        for p in $PATH; do
+          if test -f "$p/$path" && test -x "$p/$path"; then
+            new_path="$p/$path"
+            break
+          fi
+        done
+        IFS="$IFS_save"
+      else
+        # This is an absolute path, we can use it without further modifications.
+        new_path="$path"
+      fi
+
+      if test "x$new_path" = x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&6;}
+        has_space=`$ECHO "$complete" | $GREP " "`
+        if test "x$has_space" != x; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: This might be caused by spaces in the path, which is not allowed." >&5
+$as_echo "$as_me: This might be caused by spaces in the path, which is not allowed." >&6;}
+        fi
+        as_fn_error $? "Cannot locate the the path of BUILD_OBJCOPY" "$LINENO" 5
+      fi
+    fi
+
+    # Now join together the path and the arguments once again
+    if test "x$arguments" != xEOL; then
+      new_complete="$new_path ${arguments% *}"
+    else
+      new_complete="$new_path"
+    fi
+
+    if test "x$complete" != "x$new_complete"; then
+      BUILD_OBJCOPY="$new_complete"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting BUILD_OBJCOPY to \"$new_complete\"" >&5
+$as_echo "$as_me: Rewriting BUILD_OBJCOPY to \"$new_complete\"" >&6;}
+    fi
+  fi
+
+
+
+  # Publish this variable in the help.
+
+
+  if [ -z "${BUILD_STRIP+x}" ]; then
+    # The variable is not set by user, try to locate tool using the code snippet
+    for ac_prog in strip
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_BUILD_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $BUILD_STRIP in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_BUILD_STRIP="$BUILD_STRIP" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_BUILD_STRIP="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+BUILD_STRIP=$ac_cv_path_BUILD_STRIP
+if test -n "$BUILD_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_STRIP" >&5
+$as_echo "$BUILD_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$BUILD_STRIP" && break
+done
+
+  else
+    # The variable is set, but is it from the command line or the environment?
+
+    # Try to remove the string !BUILD_STRIP! from our list.
+    try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!BUILD_STRIP!/}
+    if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then
+      # If it failed, the variable was not from the command line. Ignore it,
+      # but warn the user (except for BASH, which is always set by the calling BASH).
+      if test "xBUILD_STRIP" != xBASH; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of BUILD_STRIP from the environment. Use command line variables instead." >&5
+$as_echo "$as_me: WARNING: Ignoring value of BUILD_STRIP from the environment. Use command line variables instead." >&2;}
+      fi
+      # Try to locate tool using the code snippet
+      for ac_prog in strip
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_BUILD_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $BUILD_STRIP in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_BUILD_STRIP="$BUILD_STRIP" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_BUILD_STRIP="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+BUILD_STRIP=$ac_cv_path_BUILD_STRIP
+if test -n "$BUILD_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_STRIP" >&5
+$as_echo "$BUILD_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$BUILD_STRIP" && break
+done
+
+    else
+      # If it succeeded, then it was overridden by the user. We will use it
+      # for the tool.
+
+      # First remove it from the list of overridden variables, so we can test
+      # for unknown variables in the end.
+      CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var"
+
+      # Check if we try to supply an empty value
+      if test "x$BUILD_STRIP" = x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool BUILD_STRIP= (no value)" >&5
+$as_echo "$as_me: Setting user supplied tool BUILD_STRIP= (no value)" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILD_STRIP" >&5
+$as_echo_n "checking for BUILD_STRIP... " >&6; }
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
+$as_echo "disabled" >&6; }
+      else
+        # Check if the provided tool contains a complete path.
+        tool_specified="$BUILD_STRIP"
+        tool_basename="${tool_specified##*/}"
+        if test "x$tool_basename" = "x$tool_specified"; then
+          # A command without a complete path is provided, search $PATH.
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool BUILD_STRIP=$tool_basename" >&5
+$as_echo "$as_me: Will search for user supplied tool BUILD_STRIP=$tool_basename" >&6;}
+          # Extract the first word of "$tool_basename", so it can be a program name with args.
+set dummy $tool_basename; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_BUILD_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $BUILD_STRIP in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_BUILD_STRIP="$BUILD_STRIP" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_BUILD_STRIP="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+BUILD_STRIP=$ac_cv_path_BUILD_STRIP
+if test -n "$BUILD_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_STRIP" >&5
+$as_echo "$BUILD_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+          if test "x$BUILD_STRIP" = x; then
+            as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5
+          fi
+        else
+          # Otherwise we believe it is a complete path. Use it as it is.
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool BUILD_STRIP=$tool_specified" >&5
+$as_echo "$as_me: Will use user supplied tool BUILD_STRIP=$tool_specified" >&6;}
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILD_STRIP" >&5
+$as_echo_n "checking for BUILD_STRIP... " >&6; }
+          if test ! -x "$tool_specified"; then
+            { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+            as_fn_error $? "User supplied tool BUILD_STRIP=$tool_specified does not exist or is not executable" "$LINENO" 5
+          fi
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5
+$as_echo "$tool_specified" >&6; }
+        fi
+      fi
+    fi
+
+  fi
+
+
+
+  # Only process if variable expands to non-empty
+
+  if test "x$BUILD_STRIP" != x; then
+    if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+  # First separate the path from the arguments. This will split at the first
+  # space.
+  complete="$BUILD_STRIP"
+  path="${complete%% *}"
+  tmp="$complete EOL"
+  arguments="${tmp#* }"
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  new_path=`$CYGPATH -u "$path"`
+
+  # Now try to locate executable using which
+  new_path=`$WHICH "$new_path" 2> /dev/null`
+  # bat and cmd files are not always considered executable in cygwin causing which
+  # to not find them
+  if test "x$new_path" = x \
+      && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+      && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+    new_path=`$CYGPATH -u "$path"`
+  fi
+  if test "x$new_path" = x; then
+    # Oops. Which didn't find the executable.
+    # The splitting of arguments from the executable at a space might have been incorrect,
+    # since paths with space are more likely in Windows. Give it another try with the whole
+    # argument.
+    path="$complete"
+    arguments="EOL"
+    new_path=`$CYGPATH -u "$path"`
+    new_path=`$WHICH "$new_path" 2> /dev/null`
+    # bat and cmd files are not always considered executable in cygwin causing which
+    # to not find them
+    if test "x$new_path" = x \
+        && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+        && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+      new_path=`$CYGPATH -u "$path"`
+    fi
+    if test "x$new_path" = x; then
+      # It's still not found. Now this is an unrecoverable error.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&6;}
+      has_space=`$ECHO "$complete" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5
+$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;}
+      fi
+      as_fn_error $? "Cannot locate the the path of BUILD_STRIP" "$LINENO" 5
+    fi
+  fi
+
+  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+  # "foo.exe" is OK but "foo" is an error.
+  #
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
+  # It is also a way to make sure we got the proper file name for the real test later on.
+  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+  if test "x$test_shortpath" = x; then
+    # Short path failed, file does not exist as specified.
+    # Try adding .exe or .cmd
+    if test -f "${new_path}.exe"; then
+      input_to_shortpath="${new_path}.exe"
+    elif test -f "${new_path}.cmd"; then
+      input_to_shortpath="${new_path}.cmd"
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_STRIP, which resolves as \"$new_path\", is invalid." >&5
+$as_echo "$as_me: The path of BUILD_STRIP, which resolves as \"$new_path\", is invalid." >&6;}
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&5
+$as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&6;}
+      as_fn_error $? "Cannot locate the the path of BUILD_STRIP" "$LINENO" 5
+    fi
+  else
+    input_to_shortpath="$new_path"
+  fi
+
+  # Call helper function which possibly converts this using DOS-style short mode.
+  # If so, the updated path is stored in $new_path.
+  new_path="$input_to_shortpath"
+
+  input_path="$input_to_shortpath"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+      # Going to short mode and back again did indeed matter. Since short mode is
+      # case insensitive, let's make it lowercase to improve readability.
+      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+      # Now convert it back to Unix-style (cygpath)
+      input_path=`$CYGPATH -u "$shortmode_path"`
+      new_path="$input_path"
+    fi
+  fi
+
+  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+  if test "x$test_cygdrive_prefix" = x; then
+    # As a simple fix, exclude /usr/bin since it's not a real path.
+    if test "x`$ECHO $input_to_shortpath | $GREP ^/usr/bin/`" = x; then
+      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+      # a path prefixed by /cygdrive for fixpath to work.
+      new_path="$CYGWIN_ROOT_PATH$input_path"
+    fi
+  fi
+
+  # remove trailing .exe if any
+  new_path="${new_path/%.exe/}"
+
+    elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+  # First separate the path from the arguments. This will split at the first
+  # space.
+  complete="$BUILD_STRIP"
+  path="${complete%% *}"
+  tmp="$complete EOL"
+  arguments="${tmp#* }"
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+
+  # Now try to locate executable using which
+  new_path=`$WHICH "$new_path" 2> /dev/null`
+
+  if test "x$new_path" = x; then
+    # Oops. Which didn't find the executable.
+    # The splitting of arguments from the executable at a space might have been incorrect,
+    # since paths with space are more likely in Windows. Give it another try with the whole
+    # argument.
+    path="$complete"
+    arguments="EOL"
+    new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+
+    new_path=`$WHICH "$new_path" 2> /dev/null`
+    # bat and cmd files are not always considered executable in MSYS causing which
+    # to not find them
+    if test "x$new_path" = x \
+        && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+        && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+      new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+    fi
+
+    if test "x$new_path" = x; then
+      # It's still not found. Now this is an unrecoverable error.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&6;}
+      has_space=`$ECHO "$complete" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5
+$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;}
+      fi
+      as_fn_error $? "Cannot locate the the path of BUILD_STRIP" "$LINENO" 5
+    fi
+  fi
+
+  # Now new_path has a complete unix path to the binary
+  if test "x`$ECHO $new_path | $GREP ^/bin/`" != x; then
+    # Keep paths in /bin as-is, but remove trailing .exe if any
+    new_path="${new_path/%.exe/}"
+    # Do not save /bin paths to all_fixpath_prefixes!
+  else
+    # Not in mixed or Windows style, start by that.
+    new_path=`cmd //c echo $new_path`
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+  fi
+
+    # Output is in $new_path
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+    # remove trailing .exe if any
+    new_path="${new_path/%.exe/}"
+
+    # Save the first 10 bytes of this path to the storage, so fixpath can work.
+    all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+  fi
+
+    else
+      # We're on a unix platform. Hooray! :)
+      # First separate the path from the arguments. This will split at the first
+      # space.
+      complete="$BUILD_STRIP"
+      path="${complete%% *}"
+      tmp="$complete EOL"
+      arguments="${tmp#* }"
+
+      # Cannot rely on the command "which" here since it doesn't always work.
+      is_absolute_path=`$ECHO "$path" | $GREP ^/`
+      if test -z "$is_absolute_path"; then
+        # Path to executable is not absolute. Find it.
+        IFS_save="$IFS"
+        IFS=:
+        for p in $PATH; do
+          if test -f "$p/$path" && test -x "$p/$path"; then
+            new_path="$p/$path"
+            break
+          fi
+        done
+        IFS="$IFS_save"
+      else
+        # This is an absolute path, we can use it without further modifications.
+        new_path="$path"
+      fi
+
+      if test "x$new_path" = x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&6;}
+        has_space=`$ECHO "$complete" | $GREP " "`
+        if test "x$has_space" != x; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: This might be caused by spaces in the path, which is not allowed." >&5
+$as_echo "$as_me: This might be caused by spaces in the path, which is not allowed." >&6;}
+        fi
+        as_fn_error $? "Cannot locate the the path of BUILD_STRIP" "$LINENO" 5
+      fi
+    fi
+
+    # Now join together the path and the arguments once again
+    if test "x$arguments" != xEOL; then
+      new_complete="$new_path ${arguments% *}"
+    else
+      new_complete="$new_path"
+    fi
+
+    if test "x$complete" != "x$new_complete"; then
+      BUILD_STRIP="$new_complete"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting BUILD_STRIP to \"$new_complete\"" >&5
+$as_echo "$as_me: Rewriting BUILD_STRIP to \"$new_complete\"" >&6;}
+    fi
+  fi
+
     # Assume the C compiler is the assembler
     BUILD_AS="$BUILD_CC -c"
     # Just like for the target compiler, use the compiler as linker
@@ -44530,6 +46092,8 @@
     BUILD_LDCXX="$LDCXX"
     BUILD_NM="$NM"
     BUILD_AS="$AS"
+    BUILD_OBJCOPY="$OBJCOPY"
+    BUILD_STRIP="$STRIP"
     BUILD_SYSROOT_CFLAGS="$SYSROOT_CFLAGS"
     BUILD_SYSROOT_LDFLAGS="$SYSROOT_LDFLAGS"
     BUILD_AR="$AR"
@@ -46684,9 +48248,6 @@
       ;;
   esac
 
-  # Setup LP64
-  COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK $ADD_LP64"
-
   # Set some common defines. These works for all compilers, but assume
   # -D is universally accepted.
 
@@ -46717,7 +48278,12 @@
   COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D$OPENJDK_TARGET_OS_UPPERCASE"
 
   # Setup target CPU
-  COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY"
+  OPENJDK_TARGET_CCXXFLAGS_JDK="$OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $ADD_LP64 \
+      -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY"
+  OPENJDK_BUILD_CCXXFLAGS_JDK="$OPENJDK_BUILD_CCXXFLAGS_JDK \
+      $OPENJDK_BUILD_ADD_LP64 \
+      -DARCH='\"$OPENJDK_BUILD_CPU_LEGACY\"' -D$OPENJDK_BUILD_CPU_LEGACY"
 
   # Setup debug/release defines
   if test "x$DEBUG_LEVEL" = xrelease; then
@@ -46761,12 +48327,30 @@
       -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava"
 
   # The shared libraries are compiled using the picflag.
-  CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
-  CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA"
+  CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $CFLAGS_JDK $EXTRA_CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
+  CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA"
 
   # Executable flags
-  CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK"
-  CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK"
+  CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $CFLAGS_JDK $EXTRA_CFLAGS_JDK"
+  CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \
+      $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK"
+
+  # The corresponding flags for building for the build platform. This is still an
+  # approximation, we only need something that runs on this machine when cross
+  # compiling the product.
+  OPENJDK_BUILD_CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \
+      $PICFLAG $CFLAGS_JDKLIB_EXTRA"
+  OPENJDK_BUILD_CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \
+      $PICFLAG $CXXFLAGS_JDKLIB_EXTRA"
+  OPENJDK_BUILD_CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK"
+  OPENJDK_BUILD_CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK"
+
+
+
+
 
 
 
@@ -46867,6 +48451,9 @@
     LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined"
   fi
 
+  OPENJDK_BUILD_LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE}"
+  LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} ${EXTRA_LDFLAGS_JDK}"
+
   # Customize LDFLAGS for libs
   LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
 
@@ -46877,27 +48464,36 @@
     JDKLIB_LIBS=""
   else
     LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \
-        -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}"
+        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)"
 
     # On some platforms (mac) the linker warns about non existing -L dirs.
     # Add server first if available. Linking aginst client does not always produce the same results.
     # Only add client dir if client is being built. Add minimal (note not minimal1) if only building minimal1.
     # Default to server for other variants.
     if test "x$JVM_VARIANT_SERVER" = xtrue; then
-      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/server"
+      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
     elif test "x$JVM_VARIANT_CLIENT" = xtrue; then
-      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/client"
+      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/client"
     elif test "x$JVM_VARIANT_MINIMAL1" = xtrue; then
-      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/minimal"
-    else
-      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/server"
+      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/minimal"
+    else
+      LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
     fi
 
     JDKLIB_LIBS="-ljava -ljvm"
     if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
       JDKLIB_LIBS="$JDKLIB_LIBS -lc"
     fi
-  fi
+
+    # When building a buildjdk, it's always only the server variant
+    OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \
+        -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server"
+  fi
+
+  OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_JDKLIB}"
+  LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${EXTRA_LDFLAGS_JDK}"
+
+
 
 
 
@@ -47503,6 +49099,7 @@
 
 
 
+
 # Setup debug symbols (need objcopy from the toolchain for that)
 
   #
@@ -61205,6 +62802,7 @@
     "$OUTPUT_ROOT/spec.gmk") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/spec.gmk:$AUTOCONF_DIR/spec.gmk.in" ;;
     "$OUTPUT_ROOT/hotspot-spec.gmk") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/hotspot-spec.gmk:$AUTOCONF_DIR/hotspot-spec.gmk.in" ;;
     "$OUTPUT_ROOT/bootcycle-spec.gmk") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/bootcycle-spec.gmk:$AUTOCONF_DIR/bootcycle-spec.gmk.in" ;;
+    "$OUTPUT_ROOT/buildjdk-spec.gmk") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/buildjdk-spec.gmk:$AUTOCONF_DIR/buildjdk-spec.gmk.in" ;;
     "$OUTPUT_ROOT/compare.sh") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/compare.sh:$AUTOCONF_DIR/compare.sh.in" ;;
     "$OUTPUT_ROOT/Makefile") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/Makefile:$AUTOCONF_DIR/Makefile.in" ;;
 
--- a/common/autoconf/jdk-options.m4	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/jdk-options.m4	Wed Jul 05 21:27:52 2017 +0200
@@ -405,3 +405,31 @@
 
   AC_SUBST(STATIC_BUILD)
 ])
+
+################################################################################
+#
+# jlink options. 
+# We always keep packaged modules in JDK image.
+#
+AC_DEFUN_ONCE([JDKOPT_SETUP_JLINK_OPTIONS],
+[
+  AC_ARG_ENABLE([keep-packaged-modules], [AS_HELP_STRING([--disable-keep-packaged-modules],
+    [Do not keep packaged modules in jdk image @<:@enable@:>@])])
+
+  if test "x$enable_keep_packaged_modules" = "xyes"; then
+    AC_MSG_CHECKING([if packaged modules are kept])
+    AC_MSG_RESULT([yes])
+    JLINK_KEEP_PACKAGED_MODULES=true
+  elif test "x$enable_keep_packaged_modules" = "xno"; then
+    AC_MSG_CHECKING([if packaged modules are kept])
+    AC_MSG_RESULT([no])
+    JLINK_KEEP_PACKAGED_MODULES=false
+  elif test "x$enable_keep_packaged_modules" = "x"; then
+    AC_MSG_RESULT([yes (default)])
+    JLINK_KEEP_PACKAGED_MODULES=true
+  else
+    AC_MSG_ERROR([--enable-keep-packaged-modules accepts no argument])
+  fi
+
+  AC_SUBST(JLINK_KEEP_PACKAGED_MODULES)
+])
--- a/common/autoconf/platform.m4	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/platform.m4	Wed Jul 05 21:27:52 2017 +0200
@@ -304,6 +304,37 @@
   fi
   AC_SUBST(OPENJDK_TARGET_CPU_LIBDIR)
 
+  # Now do the same for OPENJDK_BUILD_CPU...
+  # Also store the legacy naming of the cpu.
+  # Ie i586 and amd64 instead of x86 and x86_64
+  OPENJDK_BUILD_CPU_LEGACY="$OPENJDK_BUILD_CPU"
+  if test "x$OPENJDK_BUILD_CPU" = xx86; then
+    OPENJDK_BUILD_CPU_LEGACY="i586"
+  elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then
+    # On all platforms except MacOSX replace x86_64 with amd64.
+    OPENJDK_BUILD_CPU_LEGACY="amd64"
+  fi
+  AC_SUBST(OPENJDK_BUILD_CPU_LEGACY)
+
+  # And the second legacy naming of the cpu.
+  # Ie i386 and amd64 instead of x86 and x86_64.
+  OPENJDK_BUILD_CPU_LEGACY_LIB="$OPENJDK_BUILD_CPU"
+  if test "x$OPENJDK_BUILD_CPU" = xx86; then
+    OPENJDK_BUILD_CPU_LEGACY_LIB="i386"
+  elif test "x$OPENJDK_BUILD_CPU" = xx86_64; then
+    OPENJDK_BUILD_CPU_LEGACY_LIB="amd64"
+  fi
+  AC_SUBST(OPENJDK_BUILD_CPU_LEGACY_LIB)
+
+  # This is the name of the cpu (but using i386 and amd64 instead of
+  # x86 and x86_64, respectively), preceeded by a /, to be used when
+  # locating libraries. On macosx, it's empty, though.
+  OPENJDK_BUILD_CPU_LIBDIR="/$OPENJDK_BUILD_CPU_LEGACY_LIB"
+  if test "x$OPENJDK_BUILD_OS" = xmacosx; then
+    OPENJDK_BUILD_CPU_LIBDIR=""
+  fi
+  AC_SUBST(OPENJDK_BUILD_CPU_LIBDIR)
+
   # OPENJDK_TARGET_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to
   # /amd64 or /sparcv9. This string is appended to some library paths, like this:
   # /usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libexample.so
@@ -346,6 +377,24 @@
   fi
   AC_SUBST(OPENJDK_TARGET_CPU_JLI_CFLAGS)
 
+  OPENJDK_BUILD_CPU_JLI="$OPENJDK_BUILD_CPU"
+  if test "x$OPENJDK_BUILD_CPU" = xx86; then
+    OPENJDK_BUILD_CPU_JLI="i386"
+  elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then
+    # On all platforms except macosx, we replace x86_64 with amd64.
+    OPENJDK_BUILD_CPU_JLI="amd64"
+  fi
+  # Now setup the -D flags for building libjli.
+  OPENJDK_BUILD_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_BUILD_CPU_JLI\"'"
+  if test "x$OPENJDK_BUILD_OS" = xsolaris; then
+    if test "x$OPENJDK_BUILD_CPU_ARCH" = xsparc; then
+      OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'"
+    elif test "x$OPENJDK_BUILD_CPU_ARCH" = xx86; then
+      OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'"
+    fi
+  fi
+  AC_SUBST(OPENJDK_BUILD_CPU_JLI_CFLAGS)
+
   if test "x$OPENJDK_TARGET_OS" = xmacosx; then
       OPENJDK_TARGET_OS_EXPORT_DIR=macosx
   else
@@ -362,6 +411,11 @@
     fi
   fi
   AC_SUBST(LP64,$A_LP64)
+  if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then
+    if test "x$OPENJDK_BUILD_OS" = xlinux || test "x$OPENJDK_BUILD_OS" = xmacosx; then
+      OPENJDK_BUILD_ADD_LP64="-D_LP64=1"
+    fi
+  fi
 
   if test "x$COMPILE_TYPE" = "xcross"; then
     # FIXME: ... or should this include reduced builds..?
--- a/common/autoconf/source-dirs.m4	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/source-dirs.m4	Wed Jul 05 21:27:52 2017 +0200
@@ -84,3 +84,56 @@
 
   JDK_OUTPUTDIR="$OUTPUT_ROOT/jdk"
 ])
+
+################################################################################
+# Define a mechanism for importing extra prebuilt modules
+#
+
+AC_DEFUN_ONCE([SRCDIRS_SETUP_IMPORT_MODULES],
+[
+  AC_ARG_WITH(import-modules, [AS_HELP_STRING([--with-import-modules],
+      [import a set of prebuilt modules either as a zip file or an exploded directory])])
+
+  if test "x$with_import_modules" != x \
+      && test "x$with_import_modules" != "xno"; then
+    if test -d "$with_import_modules"; then
+      IMPORT_MODULES_TOPDIR="$with_import_modules"
+      BASIC_FIXUP_PATH([IMPORT_MODULES_TOPDIR])
+    elif test -e "$with_import_modules"; then
+      IMPORT_MODULES_TOPDIR="$CONFIGURESUPPORT_OUTPUTDIR/import-modules"
+      $RM -rf "$IMPORT_MODULES_TOPDIR"
+      $MKDIR -p "$IMPORT_MODULES_TOPDIR"
+      if ! $UNZIP -q "$with_import_modules" -d "$IMPORT_MODULES_TOPDIR"; then
+        AC_MSG_ERROR([--with-import-modules="$with_import_modules" must point to a dir or a zip file])
+      fi
+    else
+      AC_MSG_ERROR([--with-import-modules="$with_import_modules" must point to a dir or a zip file])
+    fi
+  fi
+
+  if test -d "$IMPORT_MODULES_TOPDIR/modules"; then
+    IMPORT_MODULES_CLASSES="$IMPORT_MODULES_TOPDIR/modules"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_cmds"; then
+    IMPORT_MODULES_CMDS="$IMPORT_MODULES_TOPDIR/modules_cmds"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_libs"; then
+    IMPORT_MODULES_LIBS="$IMPORT_MODULES_TOPDIR/modules_libs"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_conf"; then
+    IMPORT_MODULES_CONF="$IMPORT_MODULES_TOPDIR/modules_conf"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then
+    IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src"
+  fi
+  if test -d "$IMPORT_MODULES_TOPDIR/make"; then
+    IMPORT_MODULES_MAKE="$IMPORT_MODULES_TOPDIR/make"
+  fi
+
+  AC_SUBST(IMPORT_MODULES_CLASSES)
+  AC_SUBST(IMPORT_MODULES_CMDS)
+  AC_SUBST(IMPORT_MODULES_LIBS)
+  AC_SUBST(IMPORT_MODULES_CONF)
+  AC_SUBST(IMPORT_MODULES_SRC)
+  AC_SUBST(IMPORT_MODULES_MAKE)
+])
--- a/common/autoconf/spec.gmk.in	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/spec.gmk.in	Wed Jul 05 21:27:52 2017 +0200
@@ -130,6 +130,14 @@
 JAXWS_TOPDIR:=@JAXWS_TOPDIR@
 HOTSPOT_TOPDIR:=@HOTSPOT_TOPDIR@
 NASHORN_TOPDIR:=@NASHORN_TOPDIR@
+
+IMPORT_MODULES_CLASSES:=@IMPORT_MODULES_CLASSES@
+IMPORT_MODULES_CMDS:=@IMPORT_MODULES_CMDS@
+IMPORT_MODULES_LIBS:=@IMPORT_MODULES_LIBS@
+IMPORT_MODULES_CONF:=@IMPORT_MODULES_CONF@
+IMPORT_MODULES_SRC:=@IMPORT_MODULES_SRC@
+IMPORT_MODULES_MAKE:=@IMPORT_MODULES_MAKE@
+
 COPYRIGHT_YEAR:=@COPYRIGHT_YEAR@
 
 # New (JEP-223) version information
@@ -246,6 +254,7 @@
 MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support
 # This does not get overridden in a bootcycle build
 CONFIGURESUPPORT_OUTPUTDIR:=@CONFIGURESUPPORT_OUTPUTDIR@
+BUILDJDK_OUTPUTDIR=$(BUILD_OUTPUT)/buildjdk
 
 HOTSPOT_DIST=@HOTSPOT_DIST@
 
@@ -255,6 +264,9 @@
 # it in sync.
 BOOT_JDK:=@BOOT_JDK@
 
+BUILD_JDK:=@BUILD_JDK@
+CREATE_BUILDJDK:=@CREATE_BUILDJDK@
+
 # When compiling Java source to be run by the boot jdk
 # use these extra flags, eg -source 6 -target 6
 BOOT_JDK_SOURCETARGET:=@BOOT_JDK_SOURCETARGET@
@@ -405,6 +417,8 @@
 BUILD_AS:=@FIXPATH@ @BUILD_AS@
 BUILD_AR:=@FIXPATH@ @BUILD_AR@
 BUILD_NM:=@FIXPATH@ @BUILD_NM@
+BUILD_OBJCOPY:=@BUILD_OBJCOPY@
+BUILD_STRIP:=@BUILD_STRIP@
 BUILD_SYSROOT_CFLAGS:=@BUILD_SYSROOT_CFLAGS@
 BUILD_SYSROOT_LDFLAGS:=@BUILD_SYSROOT_LDFLAGS@
 
@@ -502,12 +516,40 @@
 # overriding that value by using ?=.
 JAVAC_FLAGS?=@JAVAC_FLAGS@
 
+
+BUILD_JAVA_FLAGS:=-Xms64M -Xmx1100M
+BUILD_JAVA=@FIXPATH@ $(BUILD_JDK)/bin/java $(BUILD_JAVA_FLAGS)
+
+# Use ?= as this can be overridden from bootcycle-spec.gmk
+BOOT_JDK_MODULAR ?= @BOOT_JDK_MODULAR@
+
+ifeq ($(BOOT_JDK_MODULAR), true)
+  INTERIM_OVERRIDE_MODULES_ARGS = -Xpatch:$(BUILDTOOLS_OUTPUTDIR)/override_modules
+  INTERIM_LANGTOOLS_ARGS = $(INTERIM_OVERRIDE_MODULES_ARGS)
+  JAVAC_MAIN_CLASS = -m jdk.compiler/com.sun.tools.javac.Main
+  JAVADOC_MAIN_CLASS = -m jdk.javadoc/jdk.javadoc.internal.tool.Main
+else
+  INTERIM_OVERRIDE_MODULES := java.compiler jdk.compiler \
+      jdk.jdeps jdk.javadoc jdk.rmic
+  INTERIM_OVERRIDE_MODULES_ARGS = \
+      -Xbootclasspath/p:$(call PathList, \
+          $(addprefix $(BUILDTOOLS_OUTPUTDIR)/override_modules/, \
+              $(INTERIM_OVERRIDE_MODULES)))
+  INTERIM_LANGTOOLS_ARGS = $(INTERIM_OVERRIDE_MODULES_ARGS) \
+      -cp $(BUILDTOOLS_OUTPUTDIR)/override_modules/jdk.compiler
+  JAVAC_MAIN_CLASS = com.sun.tools.javac.Main
+  JAVADOC_MAIN_CLASS = jdk.javadoc.internal.tool.Main
+endif
 # You run the new javac using the boot jdk with $(BOOT_JDK)/bin/java $(NEW_JAVAC) ...
 # Use = assignment to be able to override in bootcycle-spec.gmk
-INTERIM_LANGTOOLS_JAR = $(BUILDTOOLS_OUTPUTDIR)/interim_langtools.jar
-INTERIM_LANGTOOLS_ARGS = "-Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR)" -cp $(INTERIM_LANGTOOLS_JAR)
-NEW_JAVAC   = $(INTERIM_LANGTOOLS_ARGS) com.sun.tools.javac.Main
-NEW_JAVADOC = $(INTERIM_LANGTOOLS_ARGS) jdk.javadoc.internal.tool.Main
+NEW_JAVAC   = $(INTERIM_LANGTOOLS_ARGS) $(JAVAC_MAIN_CLASS)
+NEW_JAVADOC = $(INTERIM_LANGTOOLS_ARGS) $(JAVADOC_MAIN_CLASS)
+
+# JLink/Jmod are run using the BUILD_JDK, which is normally the jdk output dir.
+JLINK_KEEP_PACKAGED_MODULES:=@JLINK_KEEP_PACKAGED_MODULES@
+
+JLINK = @FIXPATH@ $(BUILD_JDK)/bin/jlink $(JAVA_TOOL_FLAGS_SMALL)
+JMOD = @FIXPATH@ $(BUILD_JDK)/bin/jmod $(JAVA_TOOL_FLAGS_SMALL)
 
 # Base flags for RC
 # Guarding this against resetting value. Legacy make files include spec multiple
--- a/common/autoconf/toolchain.m4	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/autoconf/toolchain.m4	Wed Jul 05 21:27:52 2017 +0200
@@ -797,6 +797,10 @@
     BASIC_FIXUP_EXECUTABLE(BUILD_NM)
     BASIC_PATH_PROGS(BUILD_AR, ar gcc-ar)
     BASIC_FIXUP_EXECUTABLE(BUILD_AR)
+    BASIC_PATH_PROGS(BUILD_OBJCOPY, objcopy)
+    BASIC_FIXUP_EXECUTABLE(BUILD_OBJCOPY)
+    BASIC_PATH_PROGS(BUILD_STRIP, strip)
+    BASIC_FIXUP_EXECUTABLE(BUILD_STRIP)
     # Assume the C compiler is the assembler
     BUILD_AS="$BUILD_CC -c"
     # Just like for the target compiler, use the compiler as linker
@@ -813,6 +817,8 @@
     BUILD_LDCXX="$LDCXX"
     BUILD_NM="$NM"
     BUILD_AS="$AS"
+    BUILD_OBJCOPY="$OBJCOPY"
+    BUILD_STRIP="$STRIP"
     BUILD_SYSROOT_CFLAGS="$SYSROOT_CFLAGS"
     BUILD_SYSROOT_LDFLAGS="$SYSROOT_LDFLAGS"
     BUILD_AR="$AR"
--- a/common/bin/compare.sh	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/bin/compare.sh	Wed Jul 05 21:27:52 2017 +0200
@@ -290,9 +290,9 @@
 
     GENERAL_FILES=$(cd $THIS_DIR && $FIND . -type f ! -name "*.so" ! -name "*.jar" \
         ! -name "*.zip" ! -name "*.debuginfo" ! -name "*.dylib" ! -name "jexec" \
-        ! -name "*.jimage" ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \
+        ! -name "modules" ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \
         ! -name "*.cpl" ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \
-        ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" \
+        ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" ! -name "*.jmod" \
         ! -name "*.obj" ! -name "*.o" ! -name "JavaControlPanelHelper" \
         ! -name "JavaUpdater" ! -name "JavaWSApplicationStub" \
         ! -name "jspawnhelper" ! -name "JavawsLauncher" ! -name "*.a" \
@@ -389,13 +389,13 @@
     $RM -rf $THIS_UNZIPDIR $OTHER_UNZIPDIR
     $MKDIR -p $THIS_UNZIPDIR
     $MKDIR -p $OTHER_UNZIPDIR
-    if [ "$TYPE" = "jimage" ]
+    if [ "$TYPE" = "jar" || "$TYPE" = "war" || "$TYPE" = "zip" || "$TYPE" = "jmod"]
     then
+        (cd $THIS_UNZIPDIR && $UNARCHIVE $THIS_ZIP)
+        (cd $OTHER_UNZIPDIR && $UNARCHIVE $OTHER_ZIP)
+    else
         (cd $THIS_UNZIPDIR && $JIMAGE extract $THIS_ZIP)
         (cd $OTHER_UNZIPDIR && $JIMAGE extract $OTHER_ZIP)
-    else
-        (cd $THIS_UNZIPDIR && $UNARCHIVE $THIS_ZIP)
-        (cd $OTHER_UNZIPDIR && $UNARCHIVE $OTHER_ZIP)
     fi
 
     # Find all archives inside and unzip them as well to compare the contents rather than
@@ -526,7 +526,7 @@
 
     # TODO filter?
     ZIPS=$(cd $THIS_DIR && $FIND . -type f -name "*.jar" -o -name "*.war" \
-        -o -name "*.jimage" | $SORT | $FILTER)
+        -o -name "modules" -o -name "*.jmod" | $SORT | $FILTER)
 
     if [ -n "$ZIPS" ]; then
         echo Jar files...
--- a/common/conf/jib-profiles.js	Thu Mar 17 19:04:16 2016 +0000
+++ b/common/conf/jib-profiles.js	Wed Jul 05 21:27:52 2017 +0200
@@ -421,10 +421,10 @@
 
         jtreg: {
             server: "javare",
-            revision: "4.1",
-            build_number: "b12",
+            revision: "4.2",
+            build_number: "b01",
             checksum_file: "MD5_VALUES",
-            file: "jtreg_bin-4.1.zip",
+            file: "jtreg_bin-4.2.zip",
             environment_name: "JT_HOME"
         },
 
--- a/hotspot/.hgtags	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/.hgtags	Wed Jul 05 21:27:52 2017 +0200
@@ -512,3 +512,4 @@
 c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107
 934f6793f5f7dca44f69b4559d525fa64b31840d jdk-9+108
 7e7e50ac4faf19899fc811569e32cfa478759ebb jdk-9+109
+2f5d1578b24060ea06bd1f340a124db95d1475b2 jdk-9+110
--- a/hotspot/make/share/makefiles/mapfile-vers	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/make/share/makefiles/mapfile-vers	Wed Jul 05 21:27:52 2017 +0200
@@ -168,3 +168,15 @@
                 JVM_TotalMemory;
                 JVM_UnloadLibrary;
                 JVM_Yield;
+
+                # Module related API's
+                JVM_AddModuleExports;
+                JVM_AddModuleExportsToAll;
+                JVM_AddModuleExportsToAllUnnamed;
+                JVM_AddModulePackage;
+                JVM_AddReadsModule;
+                JVM_CanReadModule;
+                JVM_DefineModule;
+                JVM_IsExportedToModule;
+                JVM_SetBootLoaderUnnamedModule;
+                JVM_GetModuleByPackageName;
--- a/hotspot/make/test/JtregNative.gmk	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/make/test/JtregNative.gmk	Wed Jul 05 21:27:52 2017 +0200
@@ -45,6 +45,7 @@
     $(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \
     $(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \
     $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \
+    $(HOTSPOT_TOPDIR)/test/runtime/modules/getModuleJNI \
     $(HOTSPOT_TOPDIR)/test/runtime/SameObject \
     $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \
     $(HOTSPOT_TOPDIR)/test/compiler/calls \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/module-info.java	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.hotspot.agent {
+    requires java.datatransfer;
+    requires java.desktop;
+    requires java.rmi;
+    requires java.scripting;
+    requires jdk.jcmd;
+    requires jdk.jdi;
+
+    // RMI needs to serialize types in this package
+    exports sun.jvm.hotspot.debugger.remote to java.rmi;
+    provides com.sun.jdi.connect.Connector with sun.jvm.hotspot.jdi.SACoreAttachingConnector;
+    provides com.sun.jdi.connect.Connector with sun.jvm.hotspot.jdi.SADebugServerAttachingConnector;
+    provides com.sun.jdi.connect.Connector with sun.jvm.hotspot.jdi.SAPIDAttachingConnector;
+
+    provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.JStack;
+    provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.JInfo;
+    provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.ClassLoaderStats;
+    provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.FinalizerInfo;
+    provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.HeapDumper;
+    provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.HeapSummary;
+    provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.ObjectHistogram;
+    provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.PMap;
+}
+
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java	Wed Jul 05 21:27:52 2017 +0200
@@ -31,14 +31,14 @@
 import sun.jvm.hotspot.memory.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.tools.*;
 import sun.jvm.hotspot.utilities.*;
+import jdk.internal.vm.agent.spi.ToolProvider;
 
 /**
   A command line tool to print class loader statistics.
 */
 
-public class ClassLoaderStats extends Tool {
+public class ClassLoaderStats extends Tool implements ToolProvider {
    boolean verbose = true;
 
    public ClassLoaderStats() {
@@ -49,6 +49,16 @@
       super(d);
    }
 
+   @Override
+   public String getName() {
+      return "classLoaderStats";
+   }
+
+   @Override
+   public void run(String... arguments) {
+      execute(arguments);
+   }
+
    public static void main(String[] args) {
       ClassLoaderStats cls = new ClassLoaderStats();
       cls.execute(args);
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java	Wed Jul 05 21:27:52 2017 +0200
@@ -25,24 +25,21 @@
 package sun.jvm.hotspot.tools;
 
 import sun.jvm.hotspot.debugger.JVMDebugger;
-import sun.jvm.hotspot.tools.*;
 
 import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.runtime.VM;
 import sun.jvm.hotspot.utilities.SystemDictionaryHelper;
-import sun.jvm.hotspot.utilities.ObjectReader;
-import sun.jvm.hotspot.utilities.MarkBits;
+import jdk.internal.vm.agent.spi.ToolProvider;
 
-import java.util.HashMap;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 
 /*
  * Iterates over the queue of object pending finalization and prints a
  * summary of these objects in the form of a histogram.
  */
-public class FinalizerInfo extends Tool {
+public class FinalizerInfo extends Tool implements ToolProvider {
 
     public FinalizerInfo() {
         super();
@@ -52,6 +49,16 @@
         super(d);
     }
 
+    @Override
+    public String getName() {
+        return "finalizerInfo";
+    }
+
+    @Override
+    public void run(String... arguments) {
+        execute(arguments);
+    }
+
     public static void main(String[] args) {
         FinalizerInfo finfo = new FinalizerInfo();
         finfo.execute(args);
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapDumper.java	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapDumper.java	Wed Jul 05 21:27:52 2017 +0200
@@ -26,6 +26,8 @@
 
 import sun.jvm.hotspot.utilities.HeapHprofBinWriter;
 import sun.jvm.hotspot.debugger.JVMDebugger;
+import jdk.internal.vm.agent.spi.ToolProvider;
+
 import java.io.IOException;
 
 /*
@@ -33,12 +35,16 @@
  * process/core as a HPROF binary file. It can also be used as a standalone
  * tool if required.
  */
-public class HeapDumper extends Tool {
+public class HeapDumper extends Tool implements ToolProvider {
 
     private static String DEFAULT_DUMP_FILE = "heap.bin";
 
     private String dumpFile;
 
+    public HeapDumper() {
+        this.dumpFile = DEFAULT_DUMP_FILE;
+    }
+
     public HeapDumper(String dumpFile) {
         this.dumpFile = dumpFile;
     }
@@ -48,6 +54,11 @@
         this.dumpFile = dumpFile;
     }
 
+    @Override
+    public String getName() {
+        return "heapDumper";
+    }
+
     protected void printFlagsUsage() {
         System.out.println("    <no option>\tto dump heap to " +
             DEFAULT_DUMP_FILE);
@@ -69,18 +80,22 @@
     // JDK jmap utility will always invoke this tool as:
     //   HeapDumper -f <file> <args...>
     public static void main(String args[]) {
-        String file = DEFAULT_DUMP_FILE;
+        HeapDumper dumper = new HeapDumper();
+        dumper.run(args);
+    }
+
+    @Override
+    public void run(String... args) {
         if (args.length > 2) {
             if (args[0].equals("-f")) {
-                file = args[1];
+                this.dumpFile = args[1];
                 String[] newargs = new String[args.length-2];
                 System.arraycopy(args, 2, newargs, 0, args.length-2);
                 args = newargs;
             }
         }
 
-        HeapDumper dumper = new HeapDumper(file);
-        dumper.execute(args);
+        execute(args);
     }
 
 }
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java	Wed Jul 05 21:27:52 2017 +0200
@@ -33,8 +33,9 @@
 import sun.jvm.hotspot.memory.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
+import jdk.internal.vm.agent.spi.ToolProvider;
 
-public class HeapSummary extends Tool {
+public class HeapSummary extends Tool implements ToolProvider {
 
    public HeapSummary() {
       super();
@@ -49,6 +50,16 @@
       hs.execute(args);
    }
 
+   @Override
+   public String getName() {
+      return "heapSummary";
+   }
+
+   @Override
+   public void run(String... arguments) {
+      execute(arguments);
+   }
+
    public void run() {
       CollectedHeap heap = VM.getVM().getUniverse().heap();
       VM.Flag[] flags = VM.getVM().getCommandLineFlags();
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JInfo.java	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JInfo.java	Wed Jul 05 21:27:52 2017 +0200
@@ -27,8 +27,9 @@
 import sun.jvm.hotspot.debugger.JVMDebugger;
 import sun.jvm.hotspot.runtime.Arguments;
 import sun.jvm.hotspot.runtime.VM;
+import jdk.internal.vm.agent.spi.ToolProvider;
 
-public class JInfo extends Tool {
+public class JInfo extends Tool implements ToolProvider {
     public JInfo() {
         super();
     }
@@ -94,13 +95,14 @@
         tool.run();
     }
 
-    public static void main(String[] args) {
+    @Override
+    public void run(String... args) {
         int mode = -1;
         switch (args.length) {
         case 1:
             if (args[0].charAt(0) == '-') {
                 // -h or -help or some invalid flag
-                new JInfo(mode).usage();
+                usage();
             } else {
                 mode = MODE_BOTH;
             }
@@ -114,7 +116,7 @@
                 mode = MODE_SYSPROPS;
             } else if (modeFlag.charAt(0) == '-') {
                 // -h or -help or some invalid flag
-                new JInfo(mode).usage();
+                usage();
             } else {
                 mode = MODE_BOTH;
             }
@@ -131,11 +133,16 @@
         }
 
         default:
-            new JInfo(mode).usage();
+            usage();
         }
 
-        JInfo jinfo = new JInfo(mode);
-        jinfo.execute(args);
+        this.mode = mode;
+        execute(args);
+    }
+
+    public static void main(String[] args) {
+        JInfo jinfo = new JInfo();
+        jinfo.run(args);
     }
 
     private void printVMFlags() {
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JStack.java	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JStack.java	Wed Jul 05 21:27:52 2017 +0200
@@ -25,8 +25,9 @@
 package sun.jvm.hotspot.tools;
 
 import sun.jvm.hotspot.debugger.JVMDebugger;
+import jdk.internal.vm.agent.spi.ToolProvider;
 
-public class JStack extends Tool {
+public class JStack extends Tool implements ToolProvider {
     public JStack(boolean mixedMode, boolean concurrentLocks) {
         this.mixedMode = mixedMode;
         this.concurrentLocks = concurrentLocks;
@@ -66,9 +67,8 @@
         tool.run();
     }
 
-    public static void main(String[] args) {
-        boolean mixedMode = false;
-        boolean concurrentLocks = false;
+    @Override
+    public void run(String... args) {
         int used = 0;
         for (int i = 0; i < args.length; i++) {
             if (args[i].equals("-m")) {
@@ -88,8 +88,12 @@
             args = newArgs;
         }
 
-        JStack jstack = new JStack(mixedMode, concurrentLocks);
-        jstack.execute(args);
+        execute(args);
+    }
+
+    public static void main(String[] args) {
+        JStack jstack = new JStack();
+        jstack.run(args);
     }
 
     private boolean mixedMode;
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java	Wed Jul 05 21:27:52 2017 +0200
@@ -27,11 +27,13 @@
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
+import jdk.internal.vm.agent.spi.ToolProvider;
+
 import java.io.PrintStream;
 
 /** A sample tool which uses the Serviceability Agent's APIs to obtain
     an object histogram from a remote or crashed VM. */
-public class ObjectHistogram extends Tool {
+public class ObjectHistogram extends Tool implements ToolProvider {
 
     public ObjectHistogram() {
        super();
@@ -41,6 +43,16 @@
        super(d);
     }
 
+    @Override
+    public String getName() {
+       return "objectHistogram";
+    }
+
+    @Override
+    public void run(String... arguments) {
+        execute(arguments);
+    }
+
    public void run() {
       run(System.out, System.err);
    }
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PMap.java	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PMap.java	Wed Jul 05 21:27:52 2017 +0200
@@ -28,9 +28,9 @@
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.debugger.cdbg.*;
-import sun.jvm.hotspot.runtime.*;
+import jdk.internal.vm.agent.spi.ToolProvider;
 
-public class PMap extends Tool {
+public class PMap extends Tool implements ToolProvider {
 
    public PMap() {
        super();
@@ -40,6 +40,16 @@
        super(d);
    }
 
+   @Override
+   public String getName() {
+       return "pmap";
+   }
+
+   @Override
+   public void run(String... arguments) {
+       execute(arguments);
+   }
+
    public void run() {
       run(System.out);
    }
--- a/hotspot/src/jdk.vm.ci/share/classes/META-INF/services/jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory	Thu Mar 17 19:04:16 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory
-jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory
-jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/module-info.java	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module jdk.vm.ci {
+    uses jdk.vm.ci.hotspot.HotSpotVMEventListener;
+    uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory;
+    uses jdk.vm.ci.runtime.JVMCICompilerFactory;
+
+    provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with
+        jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory;
+    provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with
+        jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory;
+    provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with
+        jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory;
+}
--- a/hotspot/src/os/posix/dtrace/hotspot_jni.d	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/os/posix/dtrace/hotspot_jni.d	Wed Jul 05 21:27:52 2017 +0200
@@ -300,6 +300,8 @@
   probe GetLongField__return(uintptr_t);
   probe GetMethodID__entry(void*, void*, const char*, const char*);
   probe GetMethodID__return(uintptr_t);
+  probe GetModule__entry(void*, void*);
+  probe GetModule__return(void*);
   probe GetObjectArrayElement__entry(void*, void*, uintptr_t);
   probe GetObjectArrayElement__return(void*);
   probe GetObjectClass__entry(void*, void*);
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -661,7 +661,7 @@
   NOT_PRODUCT(_throw_class_cast_exception_count++;)
   ResourceMark rm(thread);
   char* message = SharedRuntime::generate_class_cast_message(
-    thread, object->klass()->external_name());
+    thread, object->klass());
   SharedRuntime::throw_and_post_jvmti_exception(
     thread, vmSymbols::java_lang_ClassCastException(), message);
 JRT_END
--- a/hotspot/src/share/vm/ci/ciEnv.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -370,9 +370,9 @@
     resolved_klass = ObjArrayKlass::cast(resolved_klass)->bottom_klass();
   }
   if (resolved_klass->is_instance_klass()) {
-    return Reflection::verify_class_access(accessing_klass->get_Klass(),
-                                           resolved_klass,
-                                           true);
+    return (Reflection::verify_class_access(accessing_klass->get_Klass(),
+                                            resolved_klass,
+                                            true) == Reflection::ACCESS_OK);
   }
   return true;
 }
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/defaultMethods.hpp"
 #include "classfile/javaClasses.inline.hpp"
+#include "classfile/moduleEntry.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/verificationType.hpp"
@@ -103,8 +104,6 @@
 
 #define JAVA_9_VERSION                    53
 
-enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
-
 void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream,
                                                   ConstantPool* cp,
                                                   const int length,
@@ -1965,7 +1964,7 @@
   const vmSymbols::SID sid = vmSymbols::find_sid(name);
   // Privileged code can use all annotations.  Other code silently drops some.
   const bool privileged = loader_data->is_the_null_class_loader_data() ||
-                          loader_data->is_ext_class_loader_data() ||
+                          loader_data->is_platform_class_loader_data() ||
                           loader_data->is_anonymous();
   switch (sid) {
     case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature): {
@@ -4358,17 +4357,29 @@
 static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
   assert(this_klass != NULL, "invariant");
   const Klass* const super = this_klass->super();
-  if ((super != NULL) &&
-      (!Reflection::verify_class_access(this_klass, super, false))) {
-    ResourceMark rm(THREAD);
-    Exceptions::fthrow(
-      THREAD_AND_LOCATION,
-      vmSymbols::java_lang_IllegalAccessError(),
-      "class %s cannot access its superclass %s",
-      this_klass->external_name(),
-      super->external_name()
-    );
-    return;
+  if (super != NULL) {
+    Reflection::VerifyClassAccessResults vca_result =
+      Reflection::verify_class_access(this_klass, super, false);
+    if (vca_result != Reflection::ACCESS_OK) {
+      ResourceMark rm(THREAD);
+      char* msg =  Reflection::verify_class_access_msg(this_klass, super, vca_result);
+      if (msg == NULL) {
+        ResourceMark rm(THREAD);
+        Exceptions::fthrow(
+          THREAD_AND_LOCATION,
+          vmSymbols::java_lang_IllegalAccessError(),
+          "class %s cannot access its superclass %s",
+          this_klass->external_name(),
+          super->external_name());
+      } else {
+        // Add additional message content.
+        Exceptions::fthrow(
+          THREAD_AND_LOCATION,
+          vmSymbols::java_lang_IllegalAccessError(),
+          "superclass access check failed: %s",
+          msg);
+      }
+    }
   }
 }
 
@@ -4380,16 +4391,26 @@
   for (int i = lng - 1; i >= 0; i--) {
     Klass* const k = local_interfaces->at(i);
     assert (k != NULL && k->is_interface(), "invalid interface");
-    if (!Reflection::verify_class_access(this_klass, k, false)) {
+    Reflection::VerifyClassAccessResults vca_result =
+      Reflection::verify_class_access(this_klass, k, false);
+    if (vca_result != Reflection::ACCESS_OK) {
       ResourceMark rm(THREAD);
-      Exceptions::fthrow(
-        THREAD_AND_LOCATION,
-        vmSymbols::java_lang_IllegalAccessError(),
-        "class %s cannot access its superinterface %s",
-        this_klass->external_name(),
-        k->external_name()
-      );
-      return;
+      char* msg =  Reflection::verify_class_access_msg(this_klass, k, vca_result);
+      if (msg == NULL) {
+        Exceptions::fthrow(
+          THREAD_AND_LOCATION,
+          vmSymbols::java_lang_IllegalAccessError(),
+          "class %s cannot access its superinterface %s",
+          this_klass->external_name(),
+          k->external_name());
+      } else {
+        // Add additional message content.
+        Exceptions::fthrow(
+          THREAD_AND_LOCATION,
+          vmSymbols::java_lang_IllegalAccessError(),
+          "superinterface check failed: %s",
+          msg);
+      }
     }
   }
 }
@@ -4489,12 +4510,14 @@
   const bool is_super      = (flags & JVM_ACC_SUPER)      != 0;
   const bool is_enum       = (flags & JVM_ACC_ENUM)       != 0;
   const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0;
+  const bool is_module_info= (flags & JVM_ACC_MODULE)     != 0;
   const bool major_gte_15  = _major_version >= JAVA_1_5_VERSION;
 
   if ((is_abstract && is_final) ||
       (is_interface && !is_abstract) ||
       (is_interface && major_gte_15 && (is_super || is_enum)) ||
-      (!is_interface && major_gte_15 && is_annotation)) {
+      (!is_interface && major_gte_15 && is_annotation) ||
+      is_module_info) {
     ResourceMark rm(THREAD);
     Exceptions::fthrow(
       THREAD_AND_LOCATION,
@@ -4650,65 +4673,9 @@
                                         int length,
                                         TRAPS) const {
   assert(_need_verify, "only called when _need_verify is true");
-  int i = 0;
-  const int count = length >> 2;
-  for (int k=0; k<count; k++) {
-    unsigned char b0 = buffer[i];
-    unsigned char b1 = buffer[i+1];
-    unsigned char b2 = buffer[i+2];
-    unsigned char b3 = buffer[i+3];
-    // For an unsigned char v,
-    // (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128;
-    // (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128.
-    const unsigned char res = b0 | b0 - 1 |
-                              b1 | b1 - 1 |
-                              b2 | b2 - 1 |
-                              b3 | b3 - 1;
-    if (res >= 128) break;
-    i += 4;
+  if (!UTF8::is_legal_utf8(buffer, length, _major_version <= 47)) {
+    classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK);
   }
-  for(; i < length; i++) {
-    unsigned short c;
-    // no embedded zeros
-    guarantee_property((buffer[i] != 0), "Illegal UTF8 string in constant pool in class file %s", CHECK);
-    if(buffer[i] < 128) {
-      continue;
-    }
-    if ((i + 5) < length) { // see if it's legal supplementary character
-      if (UTF8::is_supplementary_character(&buffer[i])) {
-        c = UTF8::get_supplementary_character(&buffer[i]);
-        i += 5;
-        continue;
-      }
-    }
-    switch (buffer[i] >> 4) {
-      default: break;
-      case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
-        classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK);
-      case 0xC: case 0xD:  // 110xxxxx  10xxxxxx
-        c = (buffer[i] & 0x1F) << 6;
-        i++;
-        if ((i < length) && ((buffer[i] & 0xC0) == 0x80)) {
-          c += buffer[i] & 0x3F;
-          if (_major_version <= 47 || c == 0 || c >= 0x80) {
-            // for classes with major > 47, c must a null or a character in its shortest form
-            break;
-          }
-        }
-        classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK);
-      case 0xE:  // 1110xxxx 10xxxxxx 10xxxxxx
-        c = (buffer[i] & 0xF) << 12;
-        i += 2;
-        if ((i < length) && ((buffer[i-1] & 0xC0) == 0x80) && ((buffer[i] & 0xC0) == 0x80)) {
-          c += ((buffer[i-1] & 0x3F) << 6) + (buffer[i] & 0x3F);
-          if (_major_version <= 47 || c >= 0x800) {
-            // for classes with major > 47, c must be in its shortest form
-            break;
-          }
-        }
-        classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK);
-    }  // end of switch
-  } // end of for
 }
 
 // Unqualified names may not contain the characters '.', ';', '[', or '/'.
@@ -4716,24 +4683,35 @@
 // or <clinit>.  Note that method names may not be <init> or <clinit> in this
 // method.  Because these names have been checked as special cases before
 // calling this method in verify_legal_method_name.
-static bool verify_unqualified_name(const char* name,
-                                    unsigned int length,
-                                    int type) {
+//
+// This method is also called from the modular system APIs in modules.cpp
+// to verify the validity of module and package names.
+bool ClassFileParser::verify_unqualified_name(const char* name,
+                                              unsigned int length,
+                                              int type) {
   for (const char* p = name; p != name + length;) {
     jchar ch = *p;
     if (ch < 128) {
-      p++;
-      if (ch == '.' || ch == ';' || ch == '[') {
+      if (ch == '.') {
+        // permit '.' in module names unless it's the first char, or
+        // preceding char is also a '.', or last char is a '.'.
+        if ((type != ClassFileParser::LegalModule) ||
+          (p == name) || (*(p-1) == '.') ||
+          (p == name + length - 1)) {
+          return false;
+        }
+      }
+      if (ch == ';' || ch == '[' ) {
         return false;   // do not permit '.', ';', or '['
       }
-      if (type != LegalClass && ch == '/') {
+      if (type != ClassFileParser::LegalClass && ch == '/') {
         return false;   // do not permit '/' unless it's class name
       }
-      if (type == LegalMethod && (ch == '<' || ch == '>')) {
+      if (type == ClassFileParser::LegalMethod && (ch == '<' || ch == '>')) {
         return false;   // do not permit '<' or '>' in method names
       }
-    }
-    else {
+      p++;
+    } else {
       char* tmp_p = UTF8::next(p, &ch);
       p = tmp_p;
     }
@@ -5192,7 +5170,7 @@
   }
 }
 
-InstanceKlass* ClassFileParser::create_instance_klass(TRAPS) {
+InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) {
   if (_klass != NULL) {
     return _klass;
   }
@@ -5200,14 +5178,14 @@
   InstanceKlass* const ik =
     InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
 
-  fill_instance_klass(ik, CHECK_NULL);
+  fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL);
 
   assert(_klass == ik, "invariant");
 
   return ik;
 }
 
-void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
+void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) {
   assert(ik != NULL, "invariant");
 
   set_klass_to_deallocate(ik);
@@ -5272,6 +5250,12 @@
     ik->set_host_klass(_host_klass);
   }
 
+  // Set PackageEntry for this_klass
+  oop cl = ik->class_loader();
+  Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl));
+  ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh());
+  ik->set_package(cld, CHECK);
+
   const Array<Method*>* const methods = ik->methods();
   assert(methods != NULL, "invariant");
   const int methods_len = methods->length();
@@ -5327,10 +5311,18 @@
     }
   }
 
+  // Obtain this_klass' module entry
+  ModuleEntry* module_entry = ik->module();
+  assert(module_entry != NULL, "module_entry should always be set");
+
+  // Obtain java.lang.reflect.Module
+  Handle module_handle(THREAD, JNIHandles::resolve(module_entry->module()));
+
   // Allocate mirror and initialize static fields
   // The create_mirror() call will also call compute_modifiers()
   java_lang_Class::create_mirror(ik,
                                  _loader_data->class_loader(),
+                                 module_handle,
                                  _protection_domain,
                                  CHECK);
 
@@ -5344,6 +5336,15 @@
                                              CHECK);
   }
 
+  // Add read edges to the unnamed modules of the bootstrap and app class loaders.
+  if (changed_by_loadhook && !module_handle.is_null() && module_entry->is_named() &&
+      !module_entry->has_default_read_edges()) {
+    if (!module_entry->set_has_default_read_edges()) {
+      // We won a potential race
+      JvmtiExport::add_default_read_edges(module_handle, THREAD);
+    }
+  }
+
   // Update the loader_data graph.
   record_defined_class_dependencies(ik, CHECK);
 
@@ -5351,11 +5352,24 @@
 
   if (!is_internal()) {
     if (log_is_enabled(Info, classload)) {
-      ik->print_loading_log(LogLevel::Info, _loader_data, _stream);
-    }
-    // No 'else' here as logging levels are not mutually exclusive
-    if (log_is_enabled(Debug, classload)) {
-      ik->print_loading_log(LogLevel::Debug, _loader_data, _stream);
+      ResourceMark rm;
+      const char* module_name = NULL;
+      static const size_t modules_image_name_len = strlen(MODULES_IMAGE_NAME);
+      size_t stream_len = strlen(_stream->source());
+      // See if _stream->source() ends in "modules"
+      if (module_entry->is_named() && modules_image_name_len < stream_len &&
+        (strncmp(_stream->source() + stream_len - modules_image_name_len,
+                 MODULES_IMAGE_NAME, modules_image_name_len) == 0)) {
+        module_name = module_entry->name()->as_C_string();
+      }
+
+      if (log_is_enabled(Info, classload)) {
+        ik->print_loading_log(LogLevel::Info, _loader_data, module_name, _stream);
+      }
+      // No 'else' here as logging levels are not mutually exclusive
+      if (log_is_enabled(Debug, classload)) {
+        ik->print_loading_log(LogLevel::Debug, _loader_data, module_name, _stream);
+      }
     }
 
     if (log_is_enabled(Info, classresolve))  {
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -73,6 +73,8 @@
     NOF_PUBLICITY_LEVELS
   };
 
+  enum { LegalClass, LegalField, LegalMethod, LegalModule }; // used to verify unqualified names
+
  private:
   const ClassFileStream* _stream; // Actual input stream
   const Symbol* _requested_name;
@@ -155,7 +157,7 @@
                                   ConstantPool* cp,
                                   TRAPS);
 
-  void fill_instance_klass(InstanceKlass* ik, TRAPS);
+  void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH, TRAPS);
   void set_klass(InstanceKlass* instance);
 
   void set_class_synthetic_flag(bool x)        { _synthetic_flag = x; }
@@ -482,7 +484,7 @@
 
   ~ClassFileParser();
 
-  InstanceKlass* create_instance_klass(TRAPS);
+  InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, TRAPS);
 
   const ClassFileStream* clone_stream() const;
 
@@ -512,6 +514,7 @@
 
   bool is_internal() const { return INTERNAL == _pub_level; }
 
+  static bool verify_unqualified_name(const char* name, unsigned int length, int type);
 };
 
 #endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
--- a/hotspot/src/share/vm/classfile/classLoader.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -29,6 +29,9 @@
 #include "classfile/classLoaderExt.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/jimage.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "classfile/modules.hpp"
+#include "classfile/packageEntry.hpp"
 #include "classfile/klassFactory.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
@@ -138,11 +141,14 @@
 ClassPathEntry* ClassLoader::_first_entry         = NULL;
 ClassPathEntry* ClassLoader::_last_entry          = NULL;
 int             ClassLoader::_num_entries         = 0;
-PackageHashtable* ClassLoader::_package_hash_table = NULL;
-
+ClassPathEntry* ClassLoader::_first_append_entry = NULL;
+bool            ClassLoader::_has_jimage = false;
 #if INCLUDE_CDS
+GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL;
+GrowableArray<char*>* ClassLoader::_platform_modules_array = NULL;
 SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
 #endif
+
 // helper routines
 bool string_starts_with(const char* str, const char* str_to_find) {
   size_t str_len = strlen(str);
@@ -162,7 +168,7 @@
   return (const char*)version_string;
 }
 
-bool string_ends_with(const char* str, const char* str_to_find) {
+bool ClassLoader::string_ends_with(const char* str, const char* str_to_find) {
   size_t str_len = strlen(str);
   size_t str_to_find_len = strlen(str_to_find);
   if (str_to_find_len > str_len) {
@@ -356,15 +362,49 @@
   if (location == 0) {
     char package[JIMAGE_MAX_PATH];
     name_to_package(name, package, JIMAGE_MAX_PATH);
+
+#if INCLUDE_CDS
+    if (package[0] == '\0' && DumpSharedSpaces) {
+      return NULL;
+    }
+#endif
     if (package[0] != '\0') {
-        const char* module = (*JImagePackageToModule)(_jimage, package);
-        if (module == NULL) {
-            module = "java.base";
+      if (!Universe::is_module_initialized()) {
+        location = (*JImageFindResource)(_jimage, "java.base", get_jimage_version_string(), name, &size);
+#if INCLUDE_CDS
+        // CDS uses the boot class loader to load classes whose packages are in
+        // modules defined for other class loaders.  So, for now, get their module
+        // names from the "modules" jimage file.
+        if (DumpSharedSpaces && location == 0) {
+          const char* module_name = (*JImagePackageToModule)(_jimage, package);
+          if (module_name != NULL) {
+            location = (*JImageFindResource)(_jimage, module_name, get_jimage_version_string(), name, &size);
+          }
         }
-        location = (*JImageFindResource)(_jimage, module, get_jimage_version_string(), name, &size);
+#endif
+
+      } else {
+        // Get boot class loader's package entry table
+        PackageEntryTable* pkgEntryTable =
+          ClassLoaderData::the_null_class_loader_data()->packages();
+        // Get package's package entry
+        TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package, CHECK_NULL);
+        PackageEntry* package_entry = pkgEntryTable->lookup_only(pkg_symbol);
+
+        if (package_entry != NULL) {
+          ResourceMark rm;
+          // Get the module name
+          ModuleEntry* module = package_entry->module();
+          assert(module != NULL, "Boot classLoader package missing module");
+          assert(module->is_named(), "Boot classLoader package is in unnamed module");
+          const char* module_name = module->name()->as_C_string();
+          if (module_name != NULL) {
+            location = (*JImageFindResource)(_jimage, module_name, get_jimage_version_string(), name, &size);
+          }
+        }
+      }
     }
   }
-
   if (location != 0) {
     if (UsePerfData) {
       ClassLoader::perf_sys_classfile_bytes_read()->inc(size);
@@ -409,11 +449,11 @@
     }
   }
 }
+#endif
 
 bool ClassPathImageEntry::is_jrt() {
-  return string_ends_with(name(), BOOT_IMAGE_NAME);
+  return ClassLoader::is_jrt(name());
 }
-#endif
 
 #if INCLUDE_CDS
 void ClassLoader::exit_with_path_failure(const char* error, const char* message) {
@@ -480,7 +520,7 @@
     _shared_paths_misc_info->add_boot_classpath(sys_class_path);
   }
 #endif
-  setup_search_path(sys_class_path);
+  setup_search_path(sys_class_path, true);
 }
 
 #if INCLUDE_CDS
@@ -500,10 +540,11 @@
 }
 #endif
 
-void ClassLoader::setup_search_path(const char *class_path) {
+void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_search) {
   int offset = 0;
   int len = (int)strlen(class_path);
   int end = 0;
+  bool mark_append_entry = false;
 
   // Iterate over class path entries
   for (int start = 0; start < len; start = end) {
@@ -512,10 +553,23 @@
     }
     EXCEPTION_MARK;
     ResourceMark rm(THREAD);
+    mark_append_entry = (mark_append_entry ||
+      (bootstrap_search && (start == Arguments::bootclassloader_append_index())));
     char* path = NEW_RESOURCE_ARRAY(char, end - start + 1);
     strncpy(path, &class_path[start], end - start);
     path[end - start] = '\0';
-    update_class_path_entry_list(path, false);
+    update_class_path_entry_list(path, false, mark_append_entry, false);
+
+    // Check on the state of the boot loader's append path
+    if (mark_append_entry && (_first_append_entry == NULL)) {
+      // Failure to mark the first append entry, most likely
+      // due to a non-existent path. Record the next entry
+      // as the first boot loader append entry.
+      mark_append_entry = true;
+    } else {
+      mark_append_entry = false;
+    }
+
 #if INCLUDE_CDS
     if (DumpSharedSpaces) {
       check_shared_classpath(path);
@@ -616,6 +670,18 @@
   return NULL;
 }
 
+// The boot class loader must adhere to specfic visibility rules.
+// Prior to loading a class in a named package, the package is checked
+// to see if it is in a module defined to the boot loader. If the
+// package is not in a module defined to the boot loader, the class
+// must be loaded only in the boot loader's append path, which
+// consists of [-Xbootclasspath/a]; [jvmti appended entries]
+void ClassLoader::set_first_append_entry(ClassPathEntry *new_entry) {
+  if (_first_append_entry == NULL) {
+    _first_append_entry = new_entry;
+  }
+}
+
 // returns true if entry already on class path
 bool ClassLoader::contains_entry(ClassPathEntry *entry) {
   ClassPathEntry* e = _first_entry;
@@ -641,9 +707,31 @@
   _num_entries ++;
 }
 
+void ClassLoader::prepend_to_list(ClassPathEntry *new_entry) {
+  if (new_entry != NULL) {
+    if (_last_entry == NULL) {
+      _first_entry = _last_entry = new_entry;
+    } else {
+      new_entry->set_next(_first_entry);
+      _first_entry = new_entry;
+    }
+  }
+  _num_entries ++;
+}
+
+void ClassLoader::add_to_list(const char *apath) {
+  update_class_path_entry_list((char*)apath, false, false, false);
+}
+
+void ClassLoader::prepend_to_list(const char *apath) {
+  update_class_path_entry_list((char*)apath, false, false, true);
+}
+
 // Returns true IFF the file/dir exists and the entry was successfully created.
 bool ClassLoader::update_class_path_entry_list(const char *path,
                                                bool check_for_duplicates,
+                                               bool mark_append_entry,
+                                               bool prepend_entry,
                                                bool throw_exception) {
   struct stat st;
   if (os::stat(path, &st) == 0) {
@@ -654,12 +742,20 @@
     if (new_entry == NULL) {
       return false;
     }
-    // The kernel VM adds dynamically to the end of the classloader path and
-    // doesn't reorder the bootclasspath which would break java.lang.Package
-    // (see PackageInfo).
+
+    // Ensure that the first boot loader append entry will always be set correctly.
+    assert((!mark_append_entry ||
+            (mark_append_entry && (!check_for_duplicates || !contains_entry(new_entry)))),
+           "failed to mark boot loader's first append boundary");
+
+    // Do not reorder the bootclasspath which would break get_system_package().
     // Add new entry to linked list
+
     if (!check_for_duplicates || !contains_entry(new_entry)) {
-      ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry);
+      ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry, prepend_entry);
+      if (mark_append_entry) {
+        set_first_append_entry(new_entry);
+      }
     }
     return true;
   } else {
@@ -760,246 +856,205 @@
   return (*Crc32)(crc, (const jbyte*)buf, len);
 }
 
-// PackageInfo data exists in order to support the java.lang.Package
-// class.  A Package object provides information about a java package
-// (version, vendor, etc.) which originates in the manifest of the jar
-// file supplying the package.  For application classes, the ClassLoader
-// object takes care of this.
-
-// For system (boot) classes, the Java code in the Package class needs
-// to be able to identify which source jar file contained the boot
-// class, so that it can extract the manifest from it.  This table
-// identifies java packages with jar files in the boot classpath.
-
-// Because the boot classpath cannot change, the classpath index is
-// sufficient to identify the source jar file or directory.  (Since
-// directories have no manifests, the directory name is not required,
-// but is available.)
-
-// When using sharing -- the pathnames of entries in the boot classpath
-// may not be the same at runtime as they were when the archive was
-// created (NFS, Samba, etc.).  The actual files and directories named
-// in the classpath must be the same files, in the same order, even
-// though the exact name is not the same.
-
-class PackageInfo: public BasicHashtableEntry<mtClass> {
-public:
-  const char* _pkgname;       // Package name
-  int _classpath_index;       // Index of directory or JAR file loaded from
-
-  PackageInfo* next() {
-    return (PackageInfo*)BasicHashtableEntry<mtClass>::next();
+#if INCLUDE_CDS
+void ClassLoader::initialize_module_loader_map(JImageFile* jimage) {
+  jlong size;
+  JImageLocationRef location = (*JImageFindResource)(jimage, "java.base", get_jimage_version_string(), MODULE_LOADER_MAP, &size);
+  if (location == 0) {
+    vm_exit_during_initialization(
+      "Cannot find ModuleLoaderMap location from modules jimage.", NULL);
   }
-
-  const char* pkgname()           { return _pkgname; }
-  void set_pkgname(char* pkgname) { _pkgname = pkgname; }
-
-  const char* filename() {
-    return ClassLoader::classpath_entry(_classpath_index)->name();
+  char* buffer = NEW_RESOURCE_ARRAY(char, size);
+  jlong read = (*JImageGetResource)(jimage, location, buffer, size);
+  if (read != size) {
+    vm_exit_during_initialization(
+      "Cannot find ModuleLoaderMap resource from modules jimage.", NULL);
   }
-
-  void set_index(int index) {
-    _classpath_index = index;
-  }
-};
-
-
-class PackageHashtable : public BasicHashtable<mtClass> {
-private:
-  inline unsigned int compute_hash(const char *s, int n) {
-    unsigned int val = 0;
-    while (--n >= 0) {
-      val = *s++ + 31 * val;
-    }
-    return val;
-  }
-
-  PackageInfo* bucket(int index) {
-    return (PackageInfo*)BasicHashtable<mtClass>::bucket(index);
-  }
-
-  PackageInfo* get_entry(int index, unsigned int hash,
-                         const char* pkgname, size_t n) {
-    for (PackageInfo* pp = bucket(index); pp != NULL; pp = pp->next()) {
-      if (pp->hash() == hash &&
-          strncmp(pkgname, pp->pkgname(), n) == 0 &&
-          pp->pkgname()[n] == '\0') {
-        return pp;
+  char* char_buf = (char*)buffer;
+  int buflen = (int)strlen(char_buf);
+  char* begin_ptr = char_buf;
+  char* end_ptr = strchr(begin_ptr, '\n');
+  bool process_boot_modules = false;
+  _boot_modules_array = new (ResourceObj::C_HEAP, mtInternal)
+    GrowableArray<char*>(INITIAL_BOOT_MODULES_ARRAY_SIZE, true);
+  _platform_modules_array = new (ResourceObj::C_HEAP, mtInternal)
+    GrowableArray<char*>(INITIAL_PLATFORM_MODULES_ARRAY_SIZE, true);
+  while (end_ptr != NULL && (end_ptr - char_buf) < buflen) {
+    // Allocate a buffer from the C heap to be appended to the _boot_modules_array
+    // or the _platform_modules_array.
+    char* temp_name = NEW_C_HEAP_ARRAY(char, (size_t)(end_ptr - begin_ptr + 1), mtInternal);
+    strncpy(temp_name, begin_ptr, end_ptr - begin_ptr);
+    temp_name[end_ptr - begin_ptr] = '\0';
+    if (strncmp(temp_name, "BOOT", 4) == 0) {
+      process_boot_modules = true;
+      FREE_C_HEAP_ARRAY(char, temp_name);
+    } else if (strncmp(temp_name, "PLATFORM", 8) == 0) {
+      process_boot_modules = false;
+      FREE_C_HEAP_ARRAY(char, temp_name);
+    } else {
+      // module name
+      if (process_boot_modules) {
+        _boot_modules_array->append(temp_name);
+      } else {
+        _platform_modules_array->append(temp_name);
       }
     }
-    return NULL;
+    begin_ptr = ++end_ptr;
+    end_ptr = strchr(begin_ptr, '\n');
   }
-
-public:
-  PackageHashtable(int table_size)
-    : BasicHashtable<mtClass>(table_size, sizeof(PackageInfo)) {}
-
-  PackageHashtable(int table_size, HashtableBucket<mtClass>* t, int number_of_entries)
-    : BasicHashtable<mtClass>(table_size, sizeof(PackageInfo), t, number_of_entries) {}
-
-  PackageInfo* get_entry(const char* pkgname, int n) {
-    unsigned int hash = compute_hash(pkgname, n);
-    return get_entry(hash_to_index(hash), hash, pkgname, n);
-  }
-
-  PackageInfo* new_entry(char* pkgname, int n) {
-    unsigned int hash = compute_hash(pkgname, n);
-    PackageInfo* pp;
-    pp = (PackageInfo*)BasicHashtable<mtClass>::new_entry(hash);
-    pp->set_pkgname(pkgname);
-    return pp;
-  }
-
-  void add_entry(PackageInfo* pp) {
-    int index = hash_to_index(pp->hash());
-    BasicHashtable<mtClass>::add_entry(index, pp);
-  }
-
-  void copy_pkgnames(const char** packages) {
-    int n = 0;
-    for (int i = 0; i < table_size(); ++i) {
-      for (PackageInfo* pp = bucket(i); pp != NULL; pp = pp->next()) {
-        packages[n++] = pp->pkgname();
-      }
-    }
-    assert(n == number_of_entries(), "just checking");
-  }
-
-  CDS_ONLY(void copy_table(char** top, char* end, PackageHashtable* table);)
-};
-
-#if INCLUDE_CDS
-void PackageHashtable::copy_table(char** top, char* end,
-                                  PackageHashtable* table) {
-  // Copy (relocate) the table to the shared space.
-  BasicHashtable<mtClass>::copy_table(top, end);
-
-  // Calculate the space needed for the package name strings.
-  int i;
-  intptr_t* tableSize = (intptr_t*)(*top);
-  *top += sizeof(intptr_t);  // For table size
-  char* tableStart = *top;
-
-  for (i = 0; i < table_size(); ++i) {
-    for (PackageInfo* pp = table->bucket(i);
-                      pp != NULL;
-                      pp = pp->next()) {
-      int n1 = (int)(strlen(pp->pkgname()) + 1);
-      if (*top + n1 >= end) {
-        report_out_of_shared_space(SharedMiscData);
-      }
-      pp->set_pkgname((char*)memcpy(*top, pp->pkgname(), n1));
-      *top += n1;
-    }
-  }
-  *top = (char*)align_size_up((intptr_t)*top, sizeof(HeapWord));
-  if (*top >= end) {
-    report_out_of_shared_space(SharedMiscData);
-  }
-
-  // Write table size
-  intptr_t len = *top - (char*)tableStart;
-  *tableSize = len;
-}
-
-
-void ClassLoader::copy_package_info_buckets(char** top, char* end) {
-  _package_hash_table->copy_buckets(top, end);
-}
-
-void ClassLoader::copy_package_info_table(char** top, char* end) {
-  _package_hash_table->copy_table(top, end, _package_hash_table);
+  FREE_RESOURCE_ARRAY(u1, buffer, size);
 }
 #endif
 
-PackageInfo* ClassLoader::lookup_package(const char *pkgname) {
-  const char *cp = strrchr(pkgname, '/');
+// Function add_package extracts the package from the fully qualified class name
+// and checks if the package is in the boot loader's package entry table.  If so,
+// then it sets the classpath_index in the package entry record.
+//
+// The classpath_index field is used to find the entry on the boot loader class
+// path for packages with classes loaded by the boot loader from -Xbootclasspath/a
+// in an unnamed module.  It is also used to indicate (for all packages whose
+// classes are loaded by the boot loader) that at least one of the package's
+// classes has been loaded.
+bool ClassLoader::add_package(const char *fullq_class_name, s2 classpath_index, TRAPS) {
+  assert(fullq_class_name != NULL, "just checking");
+
+  // Get package name from fully qualified class name.
+  const char *cp = strrchr(fullq_class_name, '/');
   if (cp != NULL) {
-    // Package prefix found
-    int n = cp - pkgname + 1;
-    return _package_hash_table->get_entry(pkgname, n);
+    int len = cp - fullq_class_name;
+    PackageEntryTable* pkg_entry_tbl =
+      ClassLoaderData::the_null_class_loader_data()->packages();
+    TempNewSymbol pkg_symbol =
+      SymbolTable::new_symbol(fullq_class_name, len, CHECK_false);
+    PackageEntry* pkg_entry = pkg_entry_tbl->lookup_only(pkg_symbol);
+    if (pkg_entry != NULL) {
+      assert(classpath_index != -1, "Unexpected classpath_index");
+      pkg_entry->set_classpath_index(classpath_index);
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+oop ClassLoader::get_system_package(const char* name, TRAPS) {
+  // Look up the name in the boot loader's package entry table.
+  if (name != NULL) {
+    TempNewSymbol package_sym = SymbolTable::new_symbol(name, (int)strlen(name), CHECK_NULL);
+    // Look for the package entry in the boot loader's package entry table.
+    PackageEntry* package =
+      ClassLoaderData::the_null_class_loader_data()->packages()->lookup_only(package_sym);
+
+    // Return NULL if package does not exist or if no classes in that package
+    // have been loaded.
+    if (package != NULL && package->has_loaded_class()) {
+      ModuleEntry* module = package->module();
+      if (module->location() != NULL) {
+        ResourceMark rm(THREAD);
+        Handle ml = java_lang_String::create_from_str(
+          module->location()->as_C_string(), THREAD);
+        return ml();
+      }
+      // Return entry on boot loader class path.
+      Handle cph = java_lang_String::create_from_str(
+        ClassLoader::classpath_entry(package->classpath_index())->name(), THREAD);
+      return cph();
+    }
   }
   return NULL;
 }
 
+objArrayOop ClassLoader::get_system_packages(TRAPS) {
+  ResourceMark rm(THREAD);
+  // List of pointers to PackageEntrys that have loaded classes.
+  GrowableArray<PackageEntry*>* loaded_class_pkgs = new GrowableArray<PackageEntry*>(50);
+  {
+    MutexLocker ml(Module_lock, THREAD);
 
-bool ClassLoader::add_package(const char *pkgname, int classpath_index, TRAPS) {
-  assert(pkgname != NULL, "just checking");
-  // Bootstrap loader no longer holds system loader lock obj serializing
-  // load_instance_class and thereby add_package
-  {
-    MutexLocker ml(PackageTable_lock, THREAD);
-    // First check for previously loaded entry
-    PackageInfo* pp = lookup_package(pkgname);
-    if (pp != NULL) {
-      // Existing entry found, check source of package
-      pp->set_index(classpath_index);
-      return true;
+    PackageEntryTable* pe_table =
+      ClassLoaderData::the_null_class_loader_data()->packages();
+
+    // Collect the packages that have at least one loaded class.
+    for (int x = 0; x < pe_table->table_size(); x++) {
+      for (PackageEntry* package_entry = pe_table->bucket(x);
+           package_entry != NULL;
+           package_entry = package_entry->next()) {
+        if (package_entry->has_loaded_class()) {
+          loaded_class_pkgs->append(package_entry);
+        }
+      }
     }
+  }
 
-    const char *cp = strrchr(pkgname, '/');
-    if (cp != NULL) {
-      // Package prefix found
-      int n = cp - pkgname + 1;
 
-      char* new_pkgname = NEW_C_HEAP_ARRAY(char, n + 1, mtClass);
-      if (new_pkgname == NULL) {
-        return false;
-      }
-
-      memcpy(new_pkgname, pkgname, n);
-      new_pkgname[n] = '\0';
-      pp = _package_hash_table->new_entry(new_pkgname, n);
-      pp->set_index(classpath_index);
-
-      // Insert into hash table
-      _package_hash_table->add_entry(pp);
-    }
-    return true;
+  // Allocate objArray and fill with java.lang.String
+  objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(),
+                                           loaded_class_pkgs->length(), CHECK_NULL);
+  objArrayHandle result(THREAD, r);
+  for (int x = 0; x < loaded_class_pkgs->length(); x++) {
+    PackageEntry* package_entry = loaded_class_pkgs->at(x);
+    Handle str = java_lang_String::create_from_symbol(package_entry->name(), CHECK_NULL);
+    result->obj_at_put(x, str());
   }
+  return result();
 }
 
+#if INCLUDE_CDS
+s2 ClassLoader::module_to_classloader(const char* module_name) {
 
-oop ClassLoader::get_system_package(const char* name, TRAPS) {
-  PackageInfo* pp;
-  {
-    MutexLocker ml(PackageTable_lock, THREAD);
-    pp = lookup_package(name);
+  assert(_boot_modules_array != NULL, "_boot_modules_array is NULL");
+  assert(_platform_modules_array != NULL, "_platform_modules_array is NULL");
+
+  int array_size = _boot_modules_array->length();
+  for (int i = 0; i < array_size; i++) {
+    if (strcmp(module_name, _boot_modules_array->at(i)) == 0) {
+      return BOOT_LOADER;
+    }
   }
-  if (pp == NULL) {
-    return NULL;
-  } else {
-    Handle p = java_lang_String::create_from_str(pp->filename(), THREAD);
-    return p();
+
+  array_size = _platform_modules_array->length();
+  for (int i = 0; i < array_size; i++) {
+    if (strcmp(module_name, _platform_modules_array->at(i)) == 0) {
+      return PLATFORM_LOADER;
+    }
   }
+
+  return APP_LOADER;
+}
+#endif
+
+s2 ClassLoader::classloader_type(Symbol* class_name, ClassPathEntry* e,
+                                     int classpath_index, TRAPS) {
+#if INCLUDE_CDS
+  // obtain the classloader type based on the class name.
+  // First obtain the package name based on the class name. Then obtain
+  // the classloader type based on the package name from the jimage using
+  // a jimage API. If the classloader type cannot be found from the
+  // jimage, it is determined by the class path entry.
+  jshort loader_type = ClassLoader::APP_LOADER;
+  if (e->is_jrt()) {
+    int length = 0;
+    const jbyte* pkg_string = InstanceKlass::package_from_name(class_name, length);
+    if (pkg_string != NULL) {
+      ResourceMark rm;
+      TempNewSymbol pkg_name = SymbolTable::new_symbol((const char*)pkg_string, length, THREAD);
+      const char* pkg_name_C_string = (const char*)(pkg_name->as_C_string());
+      ClassPathImageEntry* cpie = (ClassPathImageEntry*)e;
+      JImageFile* jimage = cpie->jimage();
+      char* module_name = (char*)(*JImagePackageToModule)(jimage, pkg_name_C_string);
+      if (module_name != NULL) {
+        loader_type = ClassLoader::module_to_classloader(module_name);
+      }
+    }
+  } else if (ClassLoaderExt::is_boot_classpath(classpath_index)) {
+    loader_type = ClassLoader::BOOT_LOADER;
+  }
+  return loader_type;
+#endif
+  return ClassLoader::BOOT_LOADER; // the classloader type is ignored in non-CDS cases
 }
 
 
-objArrayOop ClassLoader::get_system_packages(TRAPS) {
-  ResourceMark rm(THREAD);
-  int nof_entries;
-  const char** packages;
-  {
-    MutexLocker ml(PackageTable_lock, THREAD);
-    // Allocate resource char* array containing package names
-    nof_entries = _package_hash_table->number_of_entries();
-    if ((packages = NEW_RESOURCE_ARRAY(const char*, nof_entries)) == NULL) {
-      return NULL;
-    }
-    _package_hash_table->copy_pkgnames(packages);
-  }
-  // Allocate objArray and fill with java.lang.String
-  objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(),
-                                           nof_entries, CHECK_0);
-  objArrayHandle result(THREAD, r);
-  for (int i = 0; i < nof_entries; i++) {
-    Handle str = java_lang_String::create_from_str(packages[i], CHECK_0);
-    result->obj_at_put(i, str());
-  }
-
-  return result();
-}
-
 // caller needs ResourceMark
 const char* ClassLoader::file_name_for_class_name(const char* class_name,
                                                   int class_name_len) {
@@ -1018,7 +1073,7 @@
   return file_name;
 }
 
-instanceKlassHandle ClassLoader::load_class(Symbol* name, TRAPS) {
+instanceKlassHandle ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS) {
 
   assert(name != NULL, "invariant");
   assert(THREAD->is_Java_thread(), "must be a JavaThread");
@@ -1037,24 +1092,54 @@
 
   ClassLoaderExt::Context context(class_name, file_name, THREAD);
 
-  // Lookup stream
+  // Lookup stream for parsing .class file
   ClassFileStream* stream = NULL;
-  int classpath_index = 0;
-  ClassPathEntry* e = _first_entry;
+  s2 classpath_index = 0;
+
+  // If DumpSharedSpaces is true, boot loader visibility boundaries are set
+  // to be _first_entry to the end (all path entries).
+  //
+  // If search_append_only is true, boot loader visibility boundaries are
+  // set to be _fist_append_entry to the end. This includes:
+  //   [-Xbootclasspath/a]; [jvmti appended entries]
+  //
+  // If both DumpSharedSpaces and search_append_only are false, boot loader
+  // visibility boundaries are set to be _first_entry to the entry before
+  // the _first_append_entry.  This would include:
+  //   [-Xpatch:<dirs>];  [exploded build | modules]
+  //
+  // DumpSharedSpaces and search_append_only are mutually exclusive and cannot
+  // be true at the same time.
+  ClassPathEntry* e = (search_append_only ? _first_append_entry : _first_entry);
+  ClassPathEntry* last_e =
+      (search_append_only || DumpSharedSpaces ? NULL : _first_append_entry);
+
   {
-    PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
-      ((JavaThread*)THREAD)->get_thread_stat()->perf_timers_addr(),
-      PerfClassTraceTime::CLASS_LOAD);
+    if (search_append_only) {
+      // For the boot loader append path search, must calculate
+      // the starting classpath_index prior to attempting to
+      // load the classfile.
+      ClassPathEntry *tmp_e = _first_entry;
+      while ((tmp_e != NULL) && (tmp_e != _first_append_entry)) {
+        tmp_e = tmp_e->next();
+        ++classpath_index;
+      }
+    }
 
-    for (; e != NULL; e = e->next(), ++classpath_index) {
+    // Attempt to load the classfile from either:
+    //   - [-Xpatch:dir]; exploded build | modules
+    //     or
+    //   - [-Xbootclasspath/a]; [jvmti appended entries]
+    while ((e != NULL) && (e != last_e)) {
       stream = e->open_stream(file_name, CHECK_NULL);
-      if (NULL == stream) {
-        continue;
-      }
       if (!context.check(stream, classpath_index)) {
         return NULL;
       }
-      break;
+      if (NULL != stream) {
+        break;
+      }
+      e = e->next();
+      ++classpath_index;
     }
   }
 
@@ -1085,32 +1170,16 @@
     return NULL;
   }
 
-  return context.record_result(classpath_index, e, result, THREAD);
+  jshort loader_type = classloader_type(name, e, classpath_index, CHECK_NULL);
+  return context.record_result(classpath_index, loader_type, e, result, THREAD);
 }
 
-void ClassLoader::create_package_info_table(HashtableBucket<mtClass> *t, int length,
-                                            int number_of_entries) {
-  assert(_package_hash_table == NULL, "One package info table allowed.");
-  assert(length == package_hash_table_size * sizeof(HashtableBucket<mtClass>),
-         "bad shared package info size.");
-  _package_hash_table = new PackageHashtable(package_hash_table_size, t,
-                                             number_of_entries);
-}
-
-
-void ClassLoader::create_package_info_table() {
-    assert(_package_hash_table == NULL, "shouldn't have one yet");
-    _package_hash_table = new PackageHashtable(package_hash_table_size);
-}
-
-
 // Initialize the class loader's access to methods in libzip.  Parse and
 // process the boot classpath into a list ClassPathEntry objects.  Once
 // this list has been created, it must not change order (see class PackageInfo)
 // it can be appended to and is by jvmti and the kernel vm.
 
 void ClassLoader::initialize() {
-  assert(_package_hash_table == NULL, "should have been initialized by now.");
   EXCEPTION_MARK;
 
   if (UsePerfData) {
@@ -1258,12 +1327,48 @@
   return true;
 }
 
-#ifndef PRODUCT
+void ClassLoader::create_javabase() {
+  Thread* THREAD = Thread::current();
 
-void ClassLoader::verify() {
-  _package_hash_table->verify();
+  // Create java.base's module entry for the boot
+  // class loader prior to loading j.l.Ojbect.
+  ClassLoaderData* null_cld = ClassLoaderData::the_null_class_loader_data();
+
+  // Get module entry table
+  ModuleEntryTable* null_cld_modules = null_cld->modules();
+  if (null_cld_modules == NULL) {
+    vm_exit_during_initialization("No ModuleEntryTable for the boot class loader");
+  }
+
+  {
+    MutexLocker ml(Module_lock, THREAD);
+    ModuleEntry* jb_module = null_cld_modules->locked_create_entry_or_null(Handle(NULL), vmSymbols::java_base(), NULL, NULL, null_cld);
+    if (jb_module == NULL) {
+      vm_exit_during_initialization("Unable to create ModuleEntry for java.base");
+    }
+    ModuleEntryTable::set_javabase_module(jb_module);
+  }
+
+  // When looking for the jimage file, only
+  // search the boot loader's module path which
+  // can consist of [-Xpatch]; exploded build | modules
+  // Do not search the boot loader's append path.
+  ClassPathEntry* e = _first_entry;
+  ClassPathEntry* last_e = _first_append_entry;
+  while ((e != NULL) && (e != last_e)) {
+    JImageFile *jimage = e->jimage();
+    if (jimage != NULL && e->is_jrt()) {
+      set_has_jimage(true);
+#if INCLUDE_CDS
+      ClassLoader::initialize_module_loader_map(jimage);
+#endif
+      return;
+    }
+    e = e->next();
+  }
 }
 
+#ifndef PRODUCT
 
 // CompileTheWorld
 //
@@ -1325,10 +1430,6 @@
   tty->cr();
 }
 
-bool ClassPathDirEntry::is_jrt() {
-  return false;
-}
-
 void ClassPathZipEntry::compile_the_world(Handle loader, TRAPS) {
   real_jzfile* zip = (real_jzfile*) _zip;
   tty->print_cr("CompileTheWorld : Compiling all classes in %s", zip->name);
@@ -1350,10 +1451,6 @@
   }
 }
 
-bool ClassPathZipEntry::is_jrt() {
-  return false;
-}
-
 void ClassLoader::compile_the_world() {
   EXCEPTION_MARK;
   HandleMark hm(THREAD);
@@ -1366,7 +1463,7 @@
   ClassPathEntry* e = _first_entry;
   jlong start = os::javaTimeMillis();
   while (e != NULL) {
-    // We stop at bootmodules.jimage, unless it is the first bootstrap path entry
+    // We stop at "modules" jimage, unless it is the first bootstrap path entry
     if (e->is_jrt() && e != _first_entry) break;
     e->compile_the_world(system_class_loader, CATCH);
     e = e->next();
--- a/hotspot/src/share/vm/classfile/classLoader.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -33,8 +33,17 @@
 // The VM class loader.
 #include <sys/stat.h>
 
-// Name of boot module image
-#define  BOOT_IMAGE_NAME "bootmodules.jimage"
+// Name of boot "modules" image
+#define  MODULES_IMAGE_NAME "modules"
+
+// Name of the resource containing mapping from module names to defining class loader type
+#define MODULE_LOADER_MAP "jdk/internal/vm/cds/resources/ModuleLoaderMap.dat"
+
+// Initial sizes of the following arrays are based on the generated ModuleLoaderMap.dat
+#define INITIAL_BOOT_MODULES_ARRAY_SIZE 30
+#define INITIAL_PLATFORM_MODULES_ARRAY_SIZE  15
+
+// Class path entry (directory or zip file)
 
 class JImageFile;
 class ClassFileStream;
@@ -49,6 +58,7 @@
     // may have unlocked readers, so write atomically.
     OrderAccess::release_store_ptr(&_next, next);
   }
+  virtual bool is_jrt() = 0;
   virtual bool is_jar_file() const = 0;
   virtual const char* name() const = 0;
   virtual JImageFile* jimage() const = 0;
@@ -59,13 +69,13 @@
   virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0;
   // Debugging
   NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;)
-    NOT_PRODUCT(virtual bool is_jrt() = 0;)
 };
 
 class ClassPathDirEntry: public ClassPathEntry {
  private:
   const char* _dir;           // Name of directory
  public:
+  bool is_jrt()            { return false; }
   bool is_jar_file() const { return false;  }
   const char* name() const { return _dir; }
   JImageFile* jimage() const { return NULL; }
@@ -73,7 +83,6 @@
   ClassFileStream* open_stream(const char* name, TRAPS);
   // Debugging
   NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
-  NOT_PRODUCT(bool is_jrt();)
 };
 
 
@@ -96,6 +105,7 @@
   jzfile* _zip;              // The zip archive
   const char*   _zip_name;   // Name of zip archive
  public:
+  bool is_jrt()            { return false; }
   bool is_jar_file() const { return true;  }
   const char* name() const { return _zip_name; }
   JImageFile* jimage() const { return NULL; }
@@ -106,7 +116,6 @@
   void contents_do(void f(const char* name, void* context), void* context);
   // Debugging
   NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
-  NOT_PRODUCT(bool is_jrt();)
 };
 
 
@@ -116,29 +125,28 @@
   JImageFile* _jimage;
   const char* _name;
 public:
+  bool is_jrt();
   bool is_jar_file() const { return false; }
   bool is_open() const { return _jimage != NULL; }
   const char* name() const { return _name == NULL ? "" : _name; }
   JImageFile* jimage() const { return _jimage; }
   ClassPathImageEntry(JImageFile* jimage, const char* name);
   ~ClassPathImageEntry();
-  static void name_to_package(const char* name, char* buffer, int length);
+  void name_to_package(const char* name, char* package, int length);
   ClassFileStream* open_stream(const char* name, TRAPS);
 
   // Debugging
   NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
-  NOT_PRODUCT(bool is_jrt();)
 };
 
-class PackageHashtable;
-class PackageInfo;
 class SharedPathsMiscInfo;
-template <MEMFLAGS F> class HashtableBucket;
 
 class ClassLoader: AllStatic {
  public:
-  enum SomeConstants {
-    package_hash_table_size = 31  // Number of buckets
+  enum ClassLoaderType {
+    BOOT_LOADER = 1,      /* boot loader */
+    PLATFORM_LOADER  = 2, /* PlatformClassLoader */
+    APP_LOADER  = 3       /* AppClassLoader */
   };
  protected:
 
@@ -177,41 +185,60 @@
   static PerfCounter* _isUnsyncloadClass;
   static PerfCounter* _load_instance_class_failCounter;
 
-  // First entry in linked list of ClassPathEntry instances
+  // First entry in linked list of ClassPathEntry instances.
+  // This consists of entries made up by:
+  //   - boot loader modules
+  //     [-Xpatch]; exploded build | modules;
+  //   - boot loader append path
+  //     [-Xbootclasspath/a]; [jvmti appended entries]
   static ClassPathEntry* _first_entry;
   // Last entry in linked list of ClassPathEntry instances
   static ClassPathEntry* _last_entry;
   static int _num_entries;
 
-  // Hash table used to keep track of loaded packages
-  static PackageHashtable* _package_hash_table;
+  // Pointer into the linked list of ClassPathEntry instances.
+  // Marks the start of:
+  //   - the boot loader's append path
+  //     [-Xbootclasspath/a]; [jvmti appended entries]
+  static ClassPathEntry* _first_append_entry;
+
   static const char* _shared_archive;
 
+  // True if the boot path has a "modules" jimage
+  static bool _has_jimage;
+
+  // Array of module names associated with the boot class loader
+  CDS_ONLY(static GrowableArray<char*>* _boot_modules_array;)
+
+  // Array of module names associated with the platform class loader
+  CDS_ONLY(static GrowableArray<char*>* _platform_modules_array;)
+
   // Info used by CDS
   CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;)
 
-  // Hash function
-  static unsigned int hash(const char *s, int n);
-  // Returns the package file name corresponding to the specified package
-  // or class name, or null if not found.
-  static PackageInfo* lookup_package(const char *pkgname);
-  // Adds a new package entry for the specified class or package name and
-  // corresponding directory or jar file name.
-  static bool add_package(const char *pkgname, int classpath_index, TRAPS);
-
   // Initialization
   static void setup_bootstrap_search_path();
-  static void setup_search_path(const char *class_path);
+  static void setup_search_path(const char *class_path, bool setting_bootstrap);
 
   static void load_zip_library();
   static void load_jimage_library();
   static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st,
                                                  bool throw_exception, TRAPS);
 
+ public:
+
+  // If the package for the fully qualified class name is in the boot
+  // loader's package entry table then add_package() sets the classpath_index
+  // field so that get_system_package() will know to return a non-null value
+  // for the package's location.  And, so that the package will be added to
+  // the list of packages returned by get_system_packages().
+  // For packages whose classes are loaded from the boot loader class path, the
+  // classpath_index indicates which entry on the boot loader class path.
+  static bool add_package(const char *fullq_class_name, s2 classpath_index, TRAPS);
+
   // Canonicalizes path names, so strcmp will work properly. This is mainly
   // to avoid confusing the zip library
   static bool get_canonical_path(const char* orig, char* out, int len);
-
   static const char* file_name_for_class_name(const char* class_name,
                                               int class_name_len);
 
@@ -220,6 +247,8 @@
   static int crc32(int crc, const char* buf, int len);
   static bool update_class_path_entry_list(const char *path,
                                            bool check_for_duplicates,
+                                           bool mark_append_entry,
+                                           bool prepend_entry,
                                            bool throw_exception=true);
   static void print_bootclasspath();
 
@@ -284,8 +313,18 @@
     return _load_instance_class_failCounter;
   }
 
+  // Sets _has_jimage to TRUE if "modules" jimage file exists
+  static void set_has_jimage(bool val) {
+    _has_jimage = val;
+  }
+
+  static bool has_jimage() { return _has_jimage; }
+
+  // Create the ModuleEntry for java.base
+  static void create_javabase();
+
   // Load individual .class file
-  static instanceKlassHandle load_class(Symbol* class_name, TRAPS);
+  static instanceKlassHandle load_class(Symbol* class_name, bool search_append_only, TRAPS);
 
   // If the specified package has been loaded by the system, then returns
   // the name of the directory or ZIP file that the package was loaded from.
@@ -304,9 +343,7 @@
   // Initialization
   static void initialize();
   CDS_ONLY(static void initialize_shared_path();)
-  static void create_package_info_table();
-  static void create_package_info_table(HashtableBucket<mtClass> *t, int length,
-                                        int number_of_entries);
+
   static int compute_Object_vtable();
 
   static ClassPathEntry* classpath_entry(int n) {
@@ -320,8 +357,6 @@
 
 #if INCLUDE_CDS
   // Sharing dump and restore
-  static void copy_package_info_buckets(char** top, char* end);
-  static void copy_package_info_table(char** top, char* end);
 
   static void  check_shared_classpath(const char *path);
   static void  finalize_shared_paths_misc_info();
@@ -329,7 +364,12 @@
   static void* get_shared_paths_misc_info();
   static bool  check_shared_paths_misc_info(void* info, int size);
   static void  exit_with_path_failure(const char* error, const char* message);
+
+  static s2 module_to_classloader(const char* module_name);
+  static void initialize_module_loader_map(JImageFile* jimage);
 #endif
+  static s2 classloader_type(Symbol* class_name, ClassPathEntry* e,
+                                 int classpath_index, TRAPS);
 
   static void  trace_class_path(const char* msg, const char* name = NULL);
 
@@ -342,15 +382,30 @@
   static jlong class_link_count();
   static jlong class_link_time_ms();
 
+  static void set_first_append_entry(ClassPathEntry* entry);
+
   // indicates if class path already contains a entry (exact match by name)
   static bool contains_entry(ClassPathEntry* entry);
 
   // adds a class path list
   static void add_to_list(ClassPathEntry* new_entry);
 
+  // prepends a class path list
+  static void prepend_to_list(ClassPathEntry* new_entry);
+
   // creates a class path zip entry (returns NULL if JAR file cannot be opened)
   static ClassPathZipEntry* create_class_path_zip_entry(const char *apath);
 
+  // add a path to class path list
+  static void add_to_list(const char* apath);
+
+  // prepend a path to class path list
+  static void prepend_to_list(const char* apath);
+
+  static bool string_ends_with(const char* str, const char* str_to_find);
+
+  static bool is_jrt(const char* name) { return string_ends_with(name, MODULES_IMAGE_NAME); }
+
   // Debugging
   static void verify()              PRODUCT_RETURN;
 
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -31,7 +31,7 @@
 //
 // Class loaders that implement a deterministic name resolution strategy
 // (including with respect to their delegation behavior), such as the boot, the
-// extension, and the system loaders of the JDK's built-in class loader
+// platform, and the system loaders of the JDK's built-in class loader
 // hierarchy, always produce the same linkset for a given configuration.
 //
 // ClassLoaderData carries information related to a linkset (e.g.,
@@ -51,6 +51,8 @@
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/metadataOnStackMark.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "classfile/packageEntry.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
 #include "gc/shared/gcLocker.hpp"
@@ -83,6 +85,7 @@
   // The null-class-loader should always be kept alive.
   _keep_alive(is_anonymous || h_class_loader.is_null()),
   _metaspace(NULL), _unloading(false), _klasses(NULL),
+  _modules(NULL), _packages(NULL),
   _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
   _next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1),
   _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
@@ -168,6 +171,30 @@
   }
 }
 
+void ClassLoaderData::modules_do(void f(ModuleEntry*)) {
+  if (_modules != NULL) {
+    for (int i = 0; i < _modules->table_size(); i++) {
+      for (ModuleEntry* entry = _modules->bucket(i);
+                              entry != NULL;
+                              entry = entry->next()) {
+        f(entry);
+      }
+    }
+  }
+}
+
+void ClassLoaderData::packages_do(void f(PackageEntry*)) {
+  if (_packages != NULL) {
+    for (int i = 0; i < _packages->table_size(); i++) {
+      for (PackageEntry* entry = _packages->bucket(i);
+                              entry != NULL;
+                              entry = entry->next()) {
+        f(entry);
+      }
+    }
+  }
+}
+
 void ClassLoaderData::record_dependency(const Klass* k, TRAPS) {
   assert(k != NULL, "invariant");
 
@@ -341,6 +368,46 @@
   }
 }
 
+PackageEntryTable* ClassLoaderData::packages() {
+  // Lazily create the package entry table at first request.
+  if (_packages == NULL) {
+    MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag);
+    // Check again if _packages has been allocated while we were getting this lock.
+    if (_packages != NULL) {
+      return _packages;
+    }
+    // Ensure _packages is stable, since it is examined without a lock
+    OrderAccess::storestore();
+    _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size);
+  }
+  return _packages;
+}
+
+ModuleEntryTable* ClassLoaderData::modules() {
+  // Lazily create the module entry table at first request.
+  if (_modules == NULL) {
+    MutexLocker m1(Module_lock);
+    // Check again if _modules has been allocated while we were getting this lock.
+    if (_modules != NULL) {
+      return _modules;
+    }
+
+    ModuleEntryTable* temp_table = new ModuleEntryTable(ModuleEntryTable::_moduletable_entry_size);
+    // Each loader has one unnamed module entry. Create it before
+    // any classes, loaded by this loader, are defined in case
+    // they end up being defined in loader's unnamed module.
+    temp_table->create_unnamed_module(this);
+
+    {
+      MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag);
+      // Ensure _modules is stable, since it is examined without a lock
+      OrderAccess::storestore();
+      _modules = temp_table;
+    }
+  }
+  return _modules;
+}
+
 oop ClassLoaderData::keep_alive_object() const {
   assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
   return is_anonymous() ? _klasses->java_mirror() : class_loader();
@@ -358,16 +425,30 @@
   // Release C heap structures for all the classes.
   classes_do(InstanceKlass::release_C_heap_structures);
 
+  // Release C heap allocated hashtable for all the packages.
+  if (_packages != NULL) {
+    // Destroy the table itself
+    delete _packages;
+    _packages = NULL;
+  }
+
+  // Release C heap allocated hashtable for all the modules.
+  if (_modules != NULL) {
+    // Destroy the table itself
+    delete _modules;
+    _modules = NULL;
+  }
+
+  // release the metaspace
   Metaspace *m = _metaspace;
   if (m != NULL) {
     _metaspace = NULL;
-    // release the metaspace
     delete m;
-    // release the handles
-    if (_handles != NULL) {
-      JNIHandleBlock::release_block(_handles);
-      _handles = NULL;
-    }
+  }
+  // release the handles
+  if (_handles != NULL) {
+    JNIHandleBlock::release_block(_handles);
+    _handles = NULL;
   }
 
   // Clear all the JNI handles for methods
@@ -389,10 +470,10 @@
 }
 
 /**
- * Returns true if this class loader data is for the extension class loader.
+ * Returns true if this class loader data is for the platform class loader.
  */
-bool ClassLoaderData::is_ext_class_loader_data() const {
-  return SystemDictionary::is_ext_class_loader(class_loader());
+bool ClassLoaderData::is_platform_class_loader_data() const {
+  return SystemDictionary::is_platform_class_loader(class_loader());
 }
 
 Metaspace* ClassLoaderData::metaspace_non_null() {
@@ -438,6 +519,10 @@
   return handles()->allocate_handle(h());
 }
 
+void ClassLoaderData::remove_handle(jobject h) {
+  _handles->release_handle(h);
+}
+
 // Add this metadata pointer to be freed when it's safe.  This is only during
 // class unloading because Handles might point to this metadata field.
 void ClassLoaderData::add_to_deallocate_list(Metadata* m) {
@@ -712,6 +797,40 @@
   }
 }
 
+void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) {
+  assert_locked_or_safepoint(Module_lock);
+  for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
+    cld->modules_do(f);
+  }
+}
+
+void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+  // Only walk the head until any clds not purged from prior unloading
+  // (CMS doesn't purge right away).
+  for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
+    assert(cld->is_unloading(), "invariant");
+    cld->modules_do(f);
+  }
+}
+
+void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) {
+  assert_locked_or_safepoint(Module_lock);
+  for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
+    cld->packages_do(f);
+  }
+}
+
+void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+  // Only walk the head until any clds not purged from prior unloading
+  // (CMS doesn't purge right away).
+  for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
+    assert(cld->is_unloading(), "invariant");
+    cld->packages_do(f);
+  }
+}
+
 void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
   for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
     cld->loaded_classes_do(klass_closure);
@@ -723,6 +842,7 @@
   // Only walk the head until any clds not purged from prior unloading
   // (CMS doesn't purge right away).
   for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
+    assert(cld->is_unloading(), "invariant");
     cld->classes_do(f);
   }
 }
@@ -800,6 +920,12 @@
   data = _head;
   while (data != NULL) {
     if (data->is_alive(is_alive_closure)) {
+      if (data->packages_defined()) {
+        data->packages()->purge_all_package_exports();
+      }
+      if (data->modules_defined()) {
+        data->modules()->purge_all_module_reads();
+      }
       // clean metaspace
       if (walk_all_metadata) {
         data->classes_do(InstanceKlass::purge_previous_versions);
@@ -992,6 +1118,7 @@
 Ticks ClassLoaderDataGraph::_class_unload_time;
 
 void ClassLoaderDataGraph::class_unload_event(Klass* const k) {
+  assert(k != NULL, "invariant");
 
   // post class unload event
   EventClassUnload event(UNTIMED);
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -53,6 +53,10 @@
 class JNIMethodBlock;
 class JNIHandleBlock;
 class Metadebug;
+class ModuleEntry;
+class PackageEntry;
+class ModuleEntryTable;
+class PackageEntryTable;
 
 // GC root for walking class loader data created
 
@@ -92,6 +96,10 @@
   static void classes_do(KlassClosure* klass_closure);
   static void classes_do(void f(Klass* const));
   static void methods_do(void f(Method*));
+  static void modules_do(void f(ModuleEntry*));
+  static void modules_unloading_do(void f(ModuleEntry*));
+  static void packages_do(void f(PackageEntry*));
+  static void packages_unloading_do(void f(PackageEntry*));
   static void loaded_classes_do(KlassClosure* klass_closure);
   static void classes_unloading_do(void f(Klass* const));
   static bool do_unloading(BoolObjectClosure* is_alive, bool clean_previous_versions);
@@ -172,9 +180,12 @@
   volatile int _claimed;   // true if claimed, for example during GC traces.
                            // To avoid applying oop closure more than once.
                            // Has to be an int because we cas it.
+  JNIHandleBlock* _handles; // Handles to constant pool arrays, Modules, etc, which
+                            // have the same life cycle of the corresponding ClassLoader.
+
   Klass* _klasses;         // The classes defined by the class loader.
-
-  JNIHandleBlock* _handles; // Handles to constant pool arrays
+  PackageEntryTable* _packages; // The packages defined by the class loader.
+  ModuleEntryTable* _modules;   // The modules defined by the class loader.
 
   // These method IDs are created for the class loader and set to NULL when the
   // class loader is unloaded.  They are rarely freed, only for redefine classes
@@ -218,6 +229,8 @@
   void loaded_classes_do(KlassClosure* klass_closure);
   void classes_do(void f(InstanceKlass*));
   void methods_do(void f(Method*));
+  void modules_do(void f(ModuleEntry*));
+  void packages_do(void f(PackageEntry*));
 
   // Deallocate free list during class unloading.
   void free_deallocate_list();
@@ -256,7 +269,7 @@
   bool is_the_null_class_loader_data() const {
     return this == _the_null_class_loader_data;
   }
-  bool is_ext_class_loader_data() const;
+  bool is_platform_class_loader_data() const;
 
   // The Metaspace is created lazily so may be NULL.  This
   // method will allocate a Metaspace if needed.
@@ -293,11 +306,16 @@
   const char* loader_name();
 
   jobject add_handle(Handle h);
+  void remove_handle(jobject h);
   void add_class(Klass* k, bool publicize = true);
   void remove_class(Klass* k);
   bool contains_klass(Klass* k);
   void record_dependency(const Klass* to, TRAPS);
   void init_dependencies(TRAPS);
+  PackageEntryTable* packages();
+  bool packages_defined() { return (_packages != NULL); }
+  ModuleEntryTable* modules();
+  bool modules_defined() { return (_modules != NULL); }
 
   void add_to_deallocate_list(Metadata* m);
 
--- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,12 +49,14 @@
       return false;
     }
 
-    instanceKlassHandle record_result(const int classpath_index,
+    instanceKlassHandle record_result(const s2 classpath_index,
+                                      const jshort classloader_type,
                                       const ClassPathEntry* e,
                                       instanceKlassHandle result, TRAPS) {
       if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
         if (DumpSharedSpaces) {
           result->set_shared_classpath_index(classpath_index);
+          result->set_class_loader_type(classloader_type);
         }
         return result;
       } else {
@@ -65,13 +67,27 @@
 
 
   static void add_class_path_entry(const char* path, bool check_for_duplicates,
-                                   ClassPathEntry* new_entry) {
-    ClassLoader::add_to_list(new_entry);
+                                   ClassPathEntry* new_entry, bool prepend_entry) {
+    if (prepend_entry) {
+      ClassLoader::prepend_to_list(new_entry);
+    } else {
+      ClassLoader::add_to_list(new_entry);
+    }
   }
   static void append_boot_classpath(ClassPathEntry* new_entry) {
     ClassLoader::add_to_list(new_entry);
+    // During jvmti live phase an entry can be appended to the boot
+    // loader's ClassPathEntry instances.  Need to mark the start
+    // of the boot loader's append path in case there was no reason
+    // to mark it initially in setup_bootstrap_search_path.
+    if (ClassLoader::_first_append_entry == NULL) {
+      ClassLoader::set_first_append_entry(new_entry);
+    }
   }
   static void setup_search_paths() {}
+  static bool is_boot_classpath(int classpath_index) {
+   return true;
+ }
   static Klass* load_one_class(ClassListParser* parser, TRAPS);
 };
 
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -24,7 +24,9 @@
 
 #include "precompiled.hpp"
 #include "classfile/altHashing.hpp"
+#include "classfile/classLoaderData.inline.hpp"
 #include "classfile/javaClasses.inline.hpp"
+#include "classfile/moduleEntry.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/debugInfo.hpp"
@@ -768,7 +770,7 @@
       }
     }
   }
-  create_mirror(k, Handle(NULL), Handle(NULL), CHECK);
+  create_mirror(k, Handle(NULL), Handle(NULL), Handle(NULL), CHECK);
 }
 
 void java_lang_Class::initialize_mirror_fields(KlassHandle k,
@@ -789,7 +791,7 @@
 }
 
 void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader,
-                                    Handle protection_domain, TRAPS) {
+                                    Handle module, Handle protection_domain, TRAPS) {
   assert(k->java_mirror() == NULL, "should only assign mirror once");
   // Use this moment of initialization to cache modifier_flags also,
   // to support Class.getModifiers().  Instance classes recalculate
@@ -849,11 +851,25 @@
     assert(class_loader() == k->class_loader(), "should be same");
     set_class_loader(mirror(), class_loader());
 
+    // set the module field in the java_lang_Class instance
+    // This may be null during bootstrap but will get fixed up later on.
+    set_module(mirror(), module());
+
     // Setup indirection from klass->mirror last
     // after any exceptions can happen during allocations.
     if (!k.is_null()) {
       k->set_java_mirror(mirror());
     }
+
+    // Keep list of classes needing java.base module fixup.
+    if (!ModuleEntryTable::javabase_defined()) {
+      if (fixup_module_field_list() == NULL) {
+        GrowableArray<Klass*>* list =
+          new (ResourceObj::C_HEAP, mtClass) GrowableArray<Klass*>(500, true);
+        set_fixup_module_field_list(list);
+      }
+      fixup_module_field_list()->push(k());
+    }
   } else {
     if (fixup_mirror_list() == NULL) {
       GrowableArray<Klass*>* list =
@@ -864,6 +880,10 @@
   }
 }
 
+void java_lang_Class::fixup_module_field(KlassHandle k, Handle module) {
+  assert(_module_offset != 0, "must have been computed already");
+  java_lang_Class::set_module(k->java_mirror(), module());
+}
 
 int  java_lang_Class::oop_size(oop java_class) {
   assert(_oop_size_offset != 0, "must be set");
@@ -931,6 +951,16 @@
   return java_class->obj_field(_class_loader_offset);
 }
 
+oop java_lang_Class::module(oop java_class) {
+  assert(_module_offset != 0, "must be set");
+  return java_class->obj_field(_module_offset);
+}
+
+void java_lang_Class::set_module(oop java_class, oop module) {
+  assert(_module_offset != 0, "must be set");
+  java_class->obj_field_put(_module_offset, module);
+}
+
 oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
   // This should be improved by adding a field at the Java level or by
   // introducing a new VM klass (see comment in ClassFileParser)
@@ -1116,6 +1146,10 @@
                  k, vmSymbols::componentType_name(),
                  vmSymbols::class_signature());
 
+  compute_offset(_module_offset,
+                 k, vmSymbols::module_name(),
+                 vmSymbols::module_signature());
+
   // Init lock is a C union with component_mirror.  Only instanceKlass mirrors have
   // init_lock and only ArrayKlass mirrors have component_mirror.  Since both are oops
   // GC treats them the same.
@@ -1668,28 +1702,48 @@
     buf_len += (int)strlen(source_file_name);
   }
 
+  char *module_name = NULL, *module_version = NULL;
+  ModuleEntry* module = holder->module();
+  if (module->is_named()) {
+    module_name = module->name()->as_C_string();
+    buf_len += (int)strlen(module_name);
+    if (module->version() != NULL) {
+      module_version = module->version()->as_C_string();
+      buf_len += (int)strlen(module_version);
+    }
+  }
+
   // Allocate temporary buffer with extra space for formatting and line number
   char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64);
 
   // Print stack trace line in buffer
-  sprintf(buf, "\tat %s.%s", klass_name, method_name);
+  sprintf(buf, "\tat %s.%s(", klass_name, method_name);
+
+  // Print module information
+  if (module_name != NULL) {
+    if (module_version != NULL) {
+      sprintf(buf + (int)strlen(buf), "%s@%s/", module_name, module_version);
+    } else {
+      sprintf(buf + (int)strlen(buf), "%s/", module_name);
+    }
+  }
 
   if (!version_matches(method, version)) {
-    strcat(buf, "(Redefined)");
+    strcat(buf, "Redefined)");
   } else {
     int line_number = Backtrace::get_line_number(method, bci);
     if (line_number == -2) {
-      strcat(buf, "(Native Method)");
+      strcat(buf, "Native Method)");
     } else {
       if (source_file_name != NULL && (line_number != -1)) {
         // Sourcename and linenumber
-        sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number);
+        sprintf(buf + (int)strlen(buf), "%s:%d)", source_file_name, line_number);
       } else if (source_file_name != NULL) {
         // Just sourcename
-        sprintf(buf + (int)strlen(buf), "(%s)", source_file_name);
+        sprintf(buf + (int)strlen(buf), "%s)", source_file_name);
       } else {
         // Neither sourcename nor linenumber
-        sprintf(buf + (int)strlen(buf), "(Unknown Source)");
+        sprintf(buf + (int)strlen(buf), "Unknown Source)");
       }
       nmethod* nm = method->code();
       if (WizardMode && nm != NULL) {
@@ -2094,6 +2148,20 @@
   oop methodname = StringTable::intern(sym, CHECK_0);
   java_lang_StackTraceElement::set_methodName(element(), methodname);
 
+  // Fill in module name and version
+  ModuleEntry* module = holder->module();
+  if (module->is_named()) {
+    oop module_name = StringTable::intern(module->name(), CHECK_0);
+    java_lang_StackTraceElement::set_moduleName(element(), module_name);
+    oop module_version;
+    if (module->version() != NULL) {
+      module_version = StringTable::intern(module->version(), CHECK_0);
+    } else {
+      module_version = NULL;
+    }
+    java_lang_StackTraceElement::set_moduleVersion(element(), module_version);
+  }
+
   if (!version_matches(method, version)) {
     // The method was redefined, accurate line number information isn't available
     java_lang_StackTraceElement::set_fileName(element(), NULL);
@@ -2753,6 +2821,80 @@
 }
 
 
+int java_lang_reflect_Module::loader_offset;
+int java_lang_reflect_Module::name_offset;
+int java_lang_reflect_Module::_module_entry_offset = -1;
+
+Handle java_lang_reflect_Module::create(Handle loader, Handle module_name, TRAPS) {
+  assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
+
+  Symbol* name = vmSymbols::java_lang_reflect_Module();
+  Klass* k = SystemDictionary::resolve_or_fail(name, true, CHECK_NH);
+  instanceKlassHandle klass (THREAD, k);
+
+  Handle jlrmh = klass->allocate_instance_handle(CHECK_NH);
+  JavaValue result(T_VOID);
+  JavaCalls::call_special(&result, jlrmh, KlassHandle(THREAD, klass()),
+                          vmSymbols::object_initializer_name(),
+                          vmSymbols::java_lang_reflect_module_init_signature(),
+                          loader, module_name, CHECK_NH);
+  return jlrmh;
+}
+
+void java_lang_reflect_Module::compute_offsets() {
+  Klass* k = SystemDictionary::reflect_Module_klass();
+  if(NULL != k) {
+    compute_offset(loader_offset,  k, vmSymbols::loader_name(),  vmSymbols::classloader_signature());
+    compute_offset(name_offset,    k, vmSymbols::name_name(),    vmSymbols::string_signature());
+    MODULE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
+  }
+}
+
+
+oop java_lang_reflect_Module::loader(oop module) {
+  assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
+  return module->obj_field(loader_offset);
+}
+
+void java_lang_reflect_Module::set_loader(oop module, oop value) {
+  assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
+  module->obj_field_put(loader_offset, value);
+}
+
+oop java_lang_reflect_Module::name(oop module) {
+  assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
+  return module->obj_field(name_offset);
+}
+
+void java_lang_reflect_Module::set_name(oop module, oop value) {
+  assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
+  module->obj_field_put(name_offset, value);
+}
+
+ModuleEntry* java_lang_reflect_Module::module_entry(oop module, TRAPS) {
+  assert(_module_entry_offset != -1, "Uninitialized module_entry_offset");
+  assert(module != NULL, "module can't be null");
+  assert(module->is_oop(), "module must be oop");
+
+  ModuleEntry* module_entry = (ModuleEntry*)module->address_field(_module_entry_offset);
+  if (module_entry == NULL) {
+    // If the inject field containing the ModuleEntry* is null then return the
+    // class loader's unnamed module.
+    oop loader = java_lang_reflect_Module::loader(module);
+    Handle h_loader = Handle(THREAD, loader);
+    ClassLoaderData* loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL);
+    return loader_cld->modules()->unnamed_module();
+  }
+  return module_entry;
+}
+
+void java_lang_reflect_Module::set_module_entry(oop module, ModuleEntry* module_entry) {
+  assert(_module_entry_offset != -1, "Uninitialized module_entry_offset");
+  assert(module != NULL, "module can't be null");
+  assert(module->is_oop(), "module must be oop");
+  module->address_field_put(_module_entry_offset, (address)module_entry);
+}
+
 Handle sun_reflect_ConstantPool::create(TRAPS) {
   assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
   Klass* k = SystemDictionary::reflect_ConstantPool_klass();
@@ -3352,6 +3494,7 @@
 bool java_lang_ClassLoader::offsets_computed = false;
 int  java_lang_ClassLoader::_loader_data_offset = -1;
 int  java_lang_ClassLoader::parallelCapable_offset = -1;
+int  java_lang_ClassLoader::unnamedModule_offset = -1;
 
 ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) {
     assert(loader != NULL && loader->is_oop(), "loader must be oop");
@@ -3371,6 +3514,9 @@
   compute_optional_offset(parallelCapable_offset,
     k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature());
 
+  compute_offset(unnamedModule_offset,
+    k1, vmSymbols::unnamedModule_name(), vmSymbols::module_signature());
+
   CLASSLOADER_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
 }
 
@@ -3438,6 +3584,10 @@
   return loader;
 }
 
+oop java_lang_ClassLoader::unnamedModule(oop loader) {
+  assert(is_instance(loader), "loader must be oop");
+  return loader->obj_field(unnamedModule_offset);
+}
 
 // Support for java_lang_System
 int java_lang_System::in_offset_in_bytes() {
@@ -3470,11 +3620,13 @@
 int java_lang_Class::_oop_size_offset;
 int java_lang_Class::_static_oop_field_count_offset;
 int java_lang_Class::_class_loader_offset;
+int java_lang_Class::_module_offset;
 int java_lang_Class::_protection_domain_offset;
 int java_lang_Class::_component_mirror_offset;
 int java_lang_Class::_init_lock_offset;
 int java_lang_Class::_signers_offset;
 GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
+GrowableArray<Klass*>* java_lang_Class::_fixup_module_field_list = NULL;
 int java_lang_Throwable::backtrace_offset;
 int java_lang_Throwable::detailMessage_offset;
 int java_lang_Throwable::cause_offset;
@@ -3534,6 +3686,8 @@
 int java_lang_StackTraceElement::methodName_offset;
 int java_lang_StackTraceElement::fileName_offset;
 int java_lang_StackTraceElement::lineNumber_offset;
+int java_lang_StackTraceElement::moduleName_offset;
+int java_lang_StackTraceElement::moduleVersion_offset;
 int java_lang_StackFrameInfo::_declaringClass_offset;
 int java_lang_StackFrameInfo::_memberName_offset;
 int java_lang_StackFrameInfo::_bci_offset;
@@ -3575,6 +3729,14 @@
   element->int_field_put(lineNumber_offset, value);
 }
 
+void java_lang_StackTraceElement::set_moduleName(oop element, oop value) {
+  element->obj_field_put(moduleName_offset, value);
+}
+
+void java_lang_StackTraceElement::set_moduleVersion(oop element, oop value) {
+  element->obj_field_put(moduleVersion_offset, value);
+}
+
 // Support for java_lang_StackFrameInfo
 void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) {
   element->obj_field_put(_declaringClass_offset, value);
@@ -3713,6 +3875,8 @@
   java_lang_System::static_security_offset = java_lang_System::hc_static_security_offset * x;
 
   // java_lang_StackTraceElement
+  java_lang_StackTraceElement::moduleName_offset = java_lang_StackTraceElement::hc_moduleName_offset * x + header;
+  java_lang_StackTraceElement::moduleVersion_offset = java_lang_StackTraceElement::hc_moduleVersion_offset * x + header;
   java_lang_StackTraceElement::declaringClass_offset = java_lang_StackTraceElement::hc_declaringClass_offset  * x + header;
   java_lang_StackTraceElement::methodName_offset = java_lang_StackTraceElement::hc_methodName_offset * x + header;
   java_lang_StackTraceElement::fileName_offset   = java_lang_StackTraceElement::hc_fileName_offset   * x + header;
@@ -3752,6 +3916,7 @@
   sun_reflect_ConstantPool::compute_offsets();
   sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
   java_lang_reflect_Parameter::compute_offsets();
+  java_lang_reflect_Module::compute_offsets();
   java_lang_StackFrameInfo::compute_offsets();
   java_lang_LiveStackFrameInfo::compute_offsets();
 
@@ -3899,7 +4064,7 @@
 
   // java.lang.ClassLoader
 
-  CHECK_OFFSET("java/lang/ClassLoader", java_lang_ClassLoader, parent,      "Ljava/lang/ClassLoader;");
+  CHECK_OFFSET("java/lang/ClassLoader", java_lang_ClassLoader, parent,        "Ljava/lang/ClassLoader;");
 
   // java.lang.System
 
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -210,12 +210,14 @@
   static int _init_lock_offset;
   static int _signers_offset;
   static int _class_loader_offset;
+  static int _module_offset;
   static int _component_mirror_offset;
 
   static bool offsets_computed;
   static int classRedefinedCount_offset;
 
   static GrowableArray<Klass*>* _fixup_mirror_list;
+  static GrowableArray<Klass*>* _fixup_module_field_list;
 
   static void set_init_lock(oop java_class, oop init_lock);
   static void set_protection_domain(oop java_class, oop protection_domain);
@@ -226,10 +228,13 @@
   static void compute_offsets();
 
   // Instance creation
-  static void create_mirror(KlassHandle k, Handle class_loader,
+  static void create_mirror(KlassHandle k, Handle class_loader, Handle module,
                             Handle protection_domain, TRAPS);
   static void fixup_mirror(KlassHandle k, TRAPS);
   static oop  create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
+
+  static void fixup_module_field(KlassHandle k, Handle module);
+
   // Conversion
   static Klass* as_Klass(oop java_class);
   static void set_klass(oop java_class, Klass* klass);
@@ -267,18 +272,29 @@
   static void set_signers(oop java_class, objArrayOop signers);
 
   static oop class_loader(oop java_class);
+  static void set_module(oop java_class, oop module);
+  static oop module(oop java_class);
 
   static int oop_size(oop java_class);
   static void set_oop_size(oop java_class, int size);
   static int static_oop_field_count(oop java_class);
   static void set_static_oop_field_count(oop java_class, int size);
 
+
   static GrowableArray<Klass*>* fixup_mirror_list() {
     return _fixup_mirror_list;
   }
   static void set_fixup_mirror_list(GrowableArray<Klass*>* v) {
     _fixup_mirror_list = v;
   }
+
+  static GrowableArray<Klass*>* fixup_module_field_list() {
+    return _fixup_module_field_list;
+  }
+  static void set_fixup_module_field_list(GrowableArray<Klass*>* v) {
+    _fixup_module_field_list = v;
+  }
+
   // Debugging
   friend class JavaClasses;
   friend class InstanceKlass;   // verification code accesses offsets
@@ -758,6 +774,39 @@
   friend class JavaClasses;
 };
 
+#define MODULE_INJECTED_FIELDS(macro)                            \
+  macro(java_lang_reflect_Module, module_entry, intptr_signature, false)
+
+class java_lang_reflect_Module {
+  private:
+    static int loader_offset;
+    static int name_offset;
+    static int _module_entry_offset;
+    static void compute_offsets();
+
+  public:
+    // Allocation
+    static Handle create(Handle loader, Handle module_name, TRAPS);
+
+    // Testers
+    static bool is_subclass(Klass* klass) {
+      return klass->is_subclass_of(SystemDictionary::reflect_Module_klass());
+    }
+    static bool is_instance(oop obj);
+
+    // Accessors
+    static oop loader(oop module);
+    static void set_loader(oop module, oop value);
+
+    static oop name(oop module);
+    static void set_name(oop module, oop value);
+
+    static ModuleEntry* module_entry(oop module, TRAPS);
+    static void set_module_entry(oop module, ModuleEntry* module_entry);
+
+  friend class JavaClasses;
+};
+
 // Interface to sun.reflect.ConstantPool objects
 class sun_reflect_ConstantPool {
  private:
@@ -1203,6 +1252,7 @@
   static bool offsets_computed;
   static int parent_offset;
   static int parallelCapable_offset;
+  static int unnamedModule_offset;
 
  public:
   static void compute_offsets();
@@ -1227,6 +1277,8 @@
   }
   static bool is_instance(oop obj);
 
+  static oop unnamedModule(oop loader);
+
   // Debugging
   friend class JavaClasses;
   friend class ClassFileParser; // access to number_of_fake_fields
@@ -1266,12 +1318,16 @@
 class java_lang_StackTraceElement: AllStatic {
  private:
   enum {
-    hc_declaringClass_offset  = 0,
-    hc_methodName_offset = 1,
-    hc_fileName_offset   = 2,
-    hc_lineNumber_offset = 3
+    hc_moduleName_offset = 0,
+    hc_moduleVersion_offset = 1,
+    hc_declaringClass_offset = 2,
+    hc_methodName_offset = 3,
+    hc_fileName_offset   = 4,
+    hc_lineNumber_offset = 5
   };
 
+  static int moduleName_offset;
+  static int moduleVersion_offset;
   static int declaringClass_offset;
   static int methodName_offset;
   static int fileName_offset;
@@ -1279,6 +1335,8 @@
 
  public:
   // Setters
+  static void set_moduleName(oop element, oop value);
+  static void set_moduleVersion(oop element, oop value);
   static void set_declaringClass(oop element, oop value);
   static void set_methodName(oop element, oop value);
   static void set_fileName(oop element, oop value);
@@ -1456,8 +1514,8 @@
   CLASSLOADER_INJECTED_FIELDS(macro)        \
   MEMBERNAME_INJECTED_FIELDS(macro)         \
   CALLSITECONTEXT_INJECTED_FIELDS(macro)    \
-  STACKFRAMEINFO_INJECTED_FIELDS(macro)
-
+  STACKFRAMEINFO_INJECTED_FIELDS(macro)     \
+  MODULE_INJECTED_FIELDS(macro)
 
 // Interface to hard-coded offset checking
 
--- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -171,6 +171,10 @@
 
 
 
+inline bool java_lang_reflect_Module::is_instance(oop obj) {
+  return obj != NULL && is_subclass(obj->klass());
+}
+
 inline int Backtrace::merge_bci_and_version(int bci, int version) {
   // only store u2 for version, checking for overflow.
   if (version > USHRT_MAX || version < 0) version = USHRT_MAX;
--- a/hotspot/src/share/vm/classfile/jimage.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/jimage.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,7 +22,7 @@
  *
  */
 
-#include "jni.h"
+#include "prims/jni.h"
 
 // Opaque reference to a JImage file.
 class JImageFile;
@@ -35,6 +35,8 @@
 
 // JImage Error Codes
 
+// Resource was not found
+#define JIMAGE_NOT_FOUND (0)
 // The image file is not prefixed with 0xCAFEDADA
 #define JIMAGE_BAD_MAGIC (-1)
 // The image file does not have a compatible (translatable) version
@@ -55,7 +57,7 @@
  *
  *  Ex.
  *   jint error;
- *   JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error);
+ *   JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules", &error);
  *   if (image == NULL) {
  *     tty->print_cr("JImage failed to open: %d", error);
  *     ...
--- a/hotspot/src/share/vm/classfile/klassFactory.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -103,11 +103,15 @@
   assert(loader_data != NULL, "invariant");
   assert(THREAD->is_Java_thread(), "must be a JavaThread");
 
+  bool changed_by_loadhook = false;
+
   ResourceMark rm;
   HandleMark hm;
 
   JvmtiCachedClassFileData* cached_class_file = NULL;
 
+  ClassFileStream* old_stream = stream;
+
   stream = prologue(stream,
                     name,
                     loader_data,
@@ -125,8 +129,8 @@
                          ClassFileParser::BROADCAST, // publicity level
                          CHECK_NULL);
 
-  instanceKlassHandle result = parser.create_instance_klass(CHECK_NULL);
-  assert(result == parser.create_instance_klass(THREAD), "invariant");
+  instanceKlassHandle result = parser.create_instance_klass(old_stream != stream, CHECK_NULL);
+  assert(result == parser.create_instance_klass(old_stream != stream, THREAD), "invariant");
 
   if (result.is_null()) {
     return NULL;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/classLoaderData.hpp"
+#include "classfile/javaClasses.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/symbol.hpp"
+#include "prims/jni.h"
+#include "runtime/handles.inline.hpp"
+#include "runtime/safepoint.hpp"
+#include "trace/traceMacros.hpp"
+#include "utilities/events.hpp"
+#include "utilities/growableArray.hpp"
+#include "utilities/hashtable.inline.hpp"
+
+ModuleEntry* ModuleEntryTable::_javabase_module = NULL;
+
+
+void ModuleEntry::set_location(Symbol* location) {
+  if (_location != NULL) {
+    // _location symbol's refcounts are managed by ModuleEntry,
+    // must decrement the old one before updating.
+    _location->decrement_refcount();
+  }
+
+  _location = location;
+
+  if (location != NULL) {
+    location->increment_refcount();
+  }
+}
+
+void ModuleEntry::set_version(Symbol* version) {
+  if (_version != NULL) {
+    // _version symbol's refcounts are managed by ModuleEntry,
+    // must decrement the old one before updating.
+    _version->decrement_refcount();
+  }
+
+  _version = version;
+
+  if (version != NULL) {
+    version->increment_refcount();
+  }
+}
+
+// Returns the shared ProtectionDomain
+Handle ModuleEntry::shared_protection_domain() {
+  return Handle(JNIHandles::resolve(_pd));
+}
+
+// Set the shared ProtectionDomain atomically
+void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data,
+                                               Handle pd_h) {
+  // Create a JNI handle for the shared ProtectionDomain and save it atomically.
+  // If someone beats us setting the _pd cache, the created JNI handle is destroyed.
+  jobject obj = loader_data->add_handle(pd_h);
+  if (Atomic::cmpxchg_ptr(obj, &_pd, NULL) != NULL) {
+    loader_data->remove_handle(obj);
+  }
+}
+
+// Returns true if this module can read module m
+bool ModuleEntry::can_read(ModuleEntry* m) const {
+  assert(m != NULL, "No module to lookup in this module's reads list");
+
+  // Unnamed modules read everyone and all modules
+  // read java.base.  If either of these conditions
+  // hold, readability has been established.
+  if (!this->is_named() ||
+      (m == ModuleEntryTable::javabase_module())) {
+    return true;
+  }
+
+  MutexLocker m1(Module_lock);
+  if (!has_reads()) {
+    return false;
+  } else {
+    return _reads->contains(m);
+  }
+}
+
+// Add a new module to this module's reads list
+void ModuleEntry::add_read(ModuleEntry* m) {
+  MutexLocker m1(Module_lock);
+  if (m == NULL) {
+    set_can_read_all_unnamed();
+  } else {
+    if (_reads == NULL) {
+      // Lazily create a module's reads list
+      _reads = new (ResourceObj::C_HEAP, mtClass)GrowableArray<ModuleEntry*>(MODULE_READS_SIZE, true);
+    }
+    _reads->append_if_missing(m);
+  }
+}
+
+bool ModuleEntry::has_reads() const {
+  assert_locked_or_safepoint(Module_lock);
+  return ((_reads != NULL) && !_reads->is_empty());
+}
+
+// Purge dead module entries out of reads list.
+void ModuleEntry::purge_reads() {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  if (has_reads()) {
+    // Go backwards because this removes entries that are dead.
+    int len = _reads->length();
+    for (int idx = len - 1; idx >= 0; idx--) {
+      ModuleEntry* module_idx = _reads->at(idx);
+      ClassLoaderData* cld = module_idx->loader();
+      if (cld->is_unloading()) {
+        _reads->delete_at(idx);
+      }
+    }
+  }
+}
+
+void ModuleEntry::module_reads_do(ModuleClosure* const f) {
+  assert_locked_or_safepoint(Module_lock);
+  assert(f != NULL, "invariant");
+
+  if (has_reads()) {
+    int reads_len = _reads->length();
+    for (int i = 0; i < reads_len; ++i) {
+      f->do_module(_reads->at(i));
+    }
+  }
+}
+
+void ModuleEntry::delete_reads() {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  delete _reads;
+  _reads = NULL;
+}
+
+ModuleEntryTable::ModuleEntryTable(int table_size)
+  : Hashtable<Symbol*, mtClass>(table_size, sizeof(ModuleEntry)), _unnamed_module(NULL)
+{
+}
+
+ModuleEntryTable::~ModuleEntryTable() {
+  assert_locked_or_safepoint(Module_lock);
+
+  // Walk through all buckets and all entries in each bucket,
+  // freeing each entry.
+  for (int i = 0; i < table_size(); ++i) {
+    for (ModuleEntry* m = bucket(i); m != NULL;) {
+      ModuleEntry* to_remove = m;
+      // read next before freeing.
+      m = m->next();
+
+      ResourceMark rm;
+      log_debug(modules)("ModuleEntryTable: deleting module: %s", to_remove->name() != NULL ?
+                         to_remove->name()->as_C_string() : UNNAMED_MODULE);
+
+      // Clean out the C heap allocated reads list first before freeing the entry
+      to_remove->delete_reads();
+      if (to_remove->name() != NULL) {
+        to_remove->name()->decrement_refcount();
+      }
+      if (to_remove->version() != NULL) {
+        to_remove->version()->decrement_refcount();
+      }
+      if (to_remove->location() != NULL) {
+        to_remove->location()->decrement_refcount();
+      }
+
+      // Unlink from the Hashtable prior to freeing
+      unlink_entry(to_remove);
+      FREE_C_HEAP_ARRAY(char, to_remove);
+    }
+  }
+  assert(number_of_entries() == 0, "should have removed all entries");
+  assert(new_entry_free_list() == NULL, "entry present on ModuleEntryTable's free list");
+  free_buckets();
+}
+
+void ModuleEntryTable::create_unnamed_module(ClassLoaderData* loader_data) {
+  assert_locked_or_safepoint(Module_lock);
+
+  // Each ModuleEntryTable has exactly one unnamed module
+  if (loader_data->is_the_null_class_loader_data()) {
+    // For the boot loader, the java.lang.reflect.Module for the unnamed module
+    // is not known until a call to JVM_SetBootLoaderUnnamedModule is made. At
+    // this point initially create the ModuleEntry for the unnamed module.
+    _unnamed_module = new_entry(0, Handle(NULL), NULL, NULL, NULL, loader_data);
+  } else {
+    // For all other class loaders the java.lang.reflect.Module for their
+    // corresponding unnamed module can be found in the java.lang.ClassLoader object.
+    oop module = java_lang_ClassLoader::unnamedModule(loader_data->class_loader());
+    _unnamed_module = new_entry(0, Handle(module), NULL, NULL, NULL, loader_data);
+
+    // Store pointer to the ModuleEntry in the unnamed module's java.lang.reflect.Module
+    // object.
+    java_lang_reflect_Module::set_module_entry(module, _unnamed_module);
+  }
+
+  // Add to bucket 0, no name to hash on
+  add_entry(0, _unnamed_module);
+}
+
+ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle, Symbol* name,
+                                         Symbol* version, Symbol* location,
+                                         ClassLoaderData* loader_data) {
+  assert_locked_or_safepoint(Module_lock);
+  ModuleEntry* entry = (ModuleEntry*) NEW_C_HEAP_ARRAY(char, entry_size(), mtClass);
+
+  // Initialize everything BasicHashtable would
+  entry->set_next(NULL);
+  entry->set_hash(hash);
+  entry->set_literal(name);
+
+  // Initialize fields specific to a ModuleEntry
+  entry->init();
+  if (name != NULL) {
+    name->increment_refcount();
+  } else {
+    // Unnamed modules can read all other unnamed modules.
+    entry->set_can_read_all_unnamed();
+  }
+
+  if (!module_handle.is_null()) {
+    entry->set_module(loader_data->add_handle(module_handle));
+  }
+
+  entry->set_loader(loader_data);
+  entry->set_version(version);
+  entry->set_location(location);
+
+  TRACE_INIT_MODULE_ID(entry);
+
+  return entry;
+}
+
+void ModuleEntryTable::add_entry(int index, ModuleEntry* new_entry) {
+  assert_locked_or_safepoint(Module_lock);
+  Hashtable<Symbol*, mtClass>::add_entry(index, (HashtableEntry<Symbol*, mtClass>*)new_entry);
+}
+
+ModuleEntry* ModuleEntryTable::locked_create_entry_or_null(Handle module_handle,
+                                                           Symbol* module_name,
+                                                           Symbol* module_version,
+                                                           Symbol* module_location,
+                                                           ClassLoaderData* loader_data) {
+  assert(module_name != NULL, "ModuleEntryTable locked_create_entry_or_null should never be called for unnamed module.");
+  assert_locked_or_safepoint(Module_lock);
+  // Check if module already exists.
+  if (lookup_only(module_name) != NULL) {
+    return NULL;
+  } else {
+    ModuleEntry* entry = new_entry(compute_hash(module_name), module_handle, module_name,
+                                   module_version, module_location, loader_data);
+    add_entry(index_for(module_name), entry);
+    return entry;
+  }
+}
+
+// lookup_only by Symbol* to find a ModuleEntry.
+ModuleEntry* ModuleEntryTable::lookup_only(Symbol* name) {
+  if (name == NULL) {
+    // Return this table's unnamed module
+    return unnamed_module();
+  }
+  int index = index_for(name);
+  for (ModuleEntry* m = bucket(index); m != NULL; m = m->next()) {
+    if (m->name()->fast_compare(name) == 0) {
+      return m;
+    }
+  }
+  return NULL;
+}
+
+// Remove dead modules from all other alive modules' reads list.
+// This should only occur at class unloading.
+void ModuleEntryTable::purge_all_module_reads() {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  for (int i = 0; i < table_size(); i++) {
+    for (ModuleEntry* entry = bucket(i);
+                      entry != NULL;
+                      entry = entry->next()) {
+      entry->purge_reads();
+    }
+  }
+}
+
+void ModuleEntryTable::finalize_javabase(Handle module_handle, Symbol* version, Symbol* location) {
+  assert_locked_or_safepoint(Module_lock);
+  ClassLoaderData* boot_loader_data = ClassLoaderData::the_null_class_loader_data();
+  ModuleEntryTable* module_table = boot_loader_data->modules();
+
+  assert(module_table != NULL, "boot loader's ModuleEntryTable not defined");
+
+  if (module_handle.is_null()) {
+    fatal("Unable to finalize module definition for java.base");
+  }
+
+  // Set java.lang.reflect.Module, version and location for java.base
+  ModuleEntry* jb_module = javabase_module();
+  assert(jb_module != NULL, "java.base ModuleEntry not defined");
+  jb_module->set_module(boot_loader_data->add_handle(module_handle));
+  jb_module->set_version(version);
+  jb_module->set_location(location);
+  // Store pointer to the ModuleEntry for java.base in the java.lang.reflect.Module object.
+  java_lang_reflect_Module::set_module_entry(module_handle(), jb_module);
+}
+
+void ModuleEntryTable::patch_javabase_entries(Handle module_handle) {
+  if (module_handle.is_null()) {
+    fatal("Unable to patch the module field of classes loaded prior to java.base's definition, invalid java.lang.reflect.Module");
+  }
+
+  // Do the fixups for the basic primitive types
+  java_lang_Class::set_module(Universe::int_mirror(), module_handle());
+  java_lang_Class::set_module(Universe::float_mirror(), module_handle());
+  java_lang_Class::set_module(Universe::double_mirror(), module_handle());
+  java_lang_Class::set_module(Universe::byte_mirror(), module_handle());
+  java_lang_Class::set_module(Universe::bool_mirror(), module_handle());
+  java_lang_Class::set_module(Universe::char_mirror(), module_handle());
+  java_lang_Class::set_module(Universe::long_mirror(), module_handle());
+  java_lang_Class::set_module(Universe::short_mirror(), module_handle());
+  java_lang_Class::set_module(Universe::void_mirror(), module_handle());
+
+  // Do the fixups for classes that have already been created.
+  GrowableArray <Klass*>* list = java_lang_Class::fixup_module_field_list();
+  int list_length = list->length();
+  for (int i = 0; i < list_length; i++) {
+    Klass* k = list->at(i);
+    assert(k->is_klass(), "List should only hold classes");
+    Thread* THREAD = Thread::current();
+    KlassHandle kh(THREAD, k);
+    java_lang_Class::fixup_module_field(kh, module_handle);
+  }
+
+  delete java_lang_Class::fixup_module_field_list();
+  java_lang_Class::set_fixup_module_field_list(NULL);
+}
+
+#ifndef PRODUCT
+void ModuleEntryTable::print() {
+  tty->print_cr("Module Entry Table (table_size=%d, entries=%d)",
+                table_size(), number_of_entries());
+  for (int i = 0; i < table_size(); i++) {
+    for (ModuleEntry* probe = bucket(i);
+                              probe != NULL;
+                              probe = probe->next()) {
+      probe->print();
+    }
+  }
+}
+
+void ModuleEntry::print() {
+  ResourceMark rm;
+  tty->print_cr("entry "PTR_FORMAT" name %s module "PTR_FORMAT" loader %s version %s location %s strict %s next "PTR_FORMAT,
+                p2i(this),
+                name() == NULL ? UNNAMED_MODULE : name()->as_C_string(),
+                p2i(module()),
+                loader()->loader_name(),
+                version() != NULL ? version()->as_C_string() : "NULL",
+                location() != NULL ? location()->as_C_string() : "NULL",
+                BOOL_TO_STR(!can_read_all_unnamed()), p2i(next()));
+}
+#endif
+
+void ModuleEntryTable::verify() {
+  int element_count = 0;
+  for (int i = 0; i < table_size(); i++) {
+    for (ModuleEntry* probe = bucket(i);
+                              probe != NULL;
+                              probe = probe->next()) {
+      probe->verify();
+      element_count++;
+    }
+  }
+  guarantee(number_of_entries() == element_count,
+            "Verify of Module Entry Table failed");
+  debug_only(verify_lookup_length((double)number_of_entries() / table_size()));
+}
+
+void ModuleEntry::verify() {
+  guarantee(loader() != NULL, "A module entry must be associated with a loader.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CLASSFILE_MODULEENTRY_HPP
+#define SHARE_VM_CLASSFILE_MODULEENTRY_HPP
+
+#include "classfile/classLoaderData.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "oops/symbol.hpp"
+#include "prims/jni.h"
+#include "runtime/mutexLocker.hpp"
+#include "trace/traceMacros.hpp"
+#include "utilities/growableArray.hpp"
+#include "utilities/hashtable.hpp"
+
+#define UNNAMED_MODULE "Unnamed Module"
+
+class ModuleClosure;
+
+// A ModuleEntry describes a module that has been defined by a call to JVM_DefineModule.
+// It contains:
+//   - Symbol* containing the module's name.
+//   - pointer to the java.lang.reflect.Module for this module.
+//   - ClassLoaderData*, class loader of this module.
+//   - a growable array containg other module entries that this module can read.
+//   - a flag indicating if this module can read all unnamed modules.
+//
+// The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either
+// data structure.
+class ModuleEntry : public HashtableEntry<Symbol*, mtClass> {
+private:
+  jobject _module;                     // java.lang.reflect.Module
+  jobject _pd;                         // java.security.ProtectionDomain, cached
+                                       // for shared classes from this module
+  ClassLoaderData* _loader;
+  GrowableArray<ModuleEntry*>* _reads; // list of modules that are readable by this module
+  Symbol* _version;                    // module version number
+  Symbol* _location;                   // module location
+  bool _can_read_all_unnamed;
+  bool _has_default_read_edges;        // JVMTI redefine/retransform support
+  TRACE_DEFINE_TRACE_ID_FIELD;
+  enum {MODULE_READS_SIZE = 101};      // Initial size of list of modules that the module can read.
+
+public:
+  void init() {
+    _module = NULL;
+    _loader = NULL;
+    _pd = NULL;
+    _reads = NULL;
+    _version = NULL;
+    _location = NULL;
+    _can_read_all_unnamed = false;
+    _has_default_read_edges = false;
+  }
+
+  Symbol*            name() const          { return literal(); }
+  void               set_name(Symbol* n)   { set_literal(n); }
+
+  jobject            module() const        { return _module; }
+  void               set_module(jobject j) { _module = j; }
+
+  // The shared ProtectionDomain reference is set once the VM loads a shared class
+  // originated from the current Module. The referenced ProtectionDomain object is
+  // created by the ClassLoader when loading a class (shared or non-shared) from the
+  // Module for the first time. This ProtectionDomain object is used for all
+  // classes from the Module loaded by the same ClassLoader.
+  Handle             shared_protection_domain();
+  void               set_shared_protection_domain(ClassLoaderData *loader_data,
+                                                  Handle pd);
+
+  ClassLoaderData*   loader() const                 { return _loader; }
+  void               set_loader(ClassLoaderData* l) { _loader = l; }
+
+  Symbol*            version() const                { return _version; }
+  void               set_version(Symbol* version);
+
+  Symbol*            location() const               { return _location; }
+  void               set_location(Symbol* location);
+
+  bool               can_read(ModuleEntry* m) const;
+  bool               has_reads() const;
+  void               add_read(ModuleEntry* m);
+
+  bool               is_named() const               { return (literal() != NULL); }
+
+  bool can_read_all_unnamed() const {
+    assert(is_named() || _can_read_all_unnamed == true,
+           "unnamed modules can always read all unnamed modules");
+    return _can_read_all_unnamed;
+  }
+
+  // Modules can only go from strict to loose.
+  void set_can_read_all_unnamed() { _can_read_all_unnamed = true; }
+
+  bool has_default_read_edges() const {
+    return _has_default_read_edges;
+  }
+
+  // Sets true and returns the previous value.
+  bool set_has_default_read_edges() {
+    MutexLocker ml(Module_lock);
+    bool prev = _has_default_read_edges;
+    _has_default_read_edges = true;
+    return prev;
+  }
+
+  ModuleEntry* next() const {
+    return (ModuleEntry*)HashtableEntry<Symbol*, mtClass>::next();
+  }
+  ModuleEntry** next_addr() {
+    return (ModuleEntry**)HashtableEntry<Symbol*, mtClass>::next_addr();
+  }
+
+  // iteration support for readability
+  void module_reads_do(ModuleClosure* const f);
+
+  TRACE_DEFINE_TRACE_ID_METHODS;
+
+  // Purge dead weak references out of reads list when any given class loader is unloaded.
+  void purge_reads();
+  void delete_reads();
+
+  void print() PRODUCT_RETURN;
+  void verify();
+};
+
+// Iterator interface
+class ModuleClosure: public StackObj {
+ public:
+  virtual void do_module(ModuleEntry* const module) = 0;
+};
+
+
+// The ModuleEntryTable is a Hashtable containing a list of all modules defined
+// by a particular class loader.  Each module is represented as a ModuleEntry node.
+//
+// Each ModuleEntryTable contains a _javabase_module field which allows for the
+// creation of java.base's ModuleEntry very early in bootstrapping before the
+// corresponding JVM_DefineModule call for java.base occurs during module system
+// initialization.  Setting up java.base's ModuleEntry early enables classes,
+// loaded prior to the module system being initialized to be created with their
+// PackageEntry node's correctly pointing at java.base's ModuleEntry.  No class
+// outside of java.base is allowed to be loaded pre-module system initialization.
+//
+// The ModuleEntryTable's lookup is lock free.
+//
+class ModuleEntryTable : public Hashtable<Symbol*, mtClass> {
+  friend class VMStructs;
+public:
+  enum Constants {
+    _moduletable_entry_size  = 109 // number of entries in module entry table
+  };
+
+private:
+  static ModuleEntry* _javabase_module;
+  ModuleEntry* _unnamed_module;
+
+  ModuleEntry* new_entry(unsigned int hash, Handle module_handle, Symbol* name, Symbol* version,
+                         Symbol* location, ClassLoaderData* class_loader);
+  void add_entry(int index, ModuleEntry* new_entry);
+
+  int entry_size() const { return BasicHashtable<mtClass>::entry_size(); }
+
+  ModuleEntry** bucket_addr(int i) {
+    return (ModuleEntry**)Hashtable<Symbol*, mtClass>::bucket_addr(i);
+  }
+
+  static unsigned int compute_hash(Symbol* name) { return ((name == NULL) ? 0 : (unsigned int)(name->identity_hash())); }
+  int index_for(Symbol* name) const              { return hash_to_index(compute_hash(name)); }
+
+public:
+  ModuleEntryTable(int table_size);
+  ~ModuleEntryTable();
+
+  ModuleEntry* bucket(int i) {
+    return (ModuleEntry*)Hashtable<Symbol*, mtClass>::bucket(i);
+  }
+
+  // Create module in loader's module entry table, if already exists then
+  // return null.  Assume Module_lock has been locked by caller.
+  ModuleEntry* locked_create_entry_or_null(Handle module_handle,
+                                           Symbol* module_name,
+                                           Symbol* module_version,
+                                           Symbol* module_location,
+                                           ClassLoaderData* loader_data);
+
+  // Only lookup module within loader's module entry table.  The table read is lock-free.
+  ModuleEntry* lookup_only(Symbol* name);
+
+  // purge dead weak references out of reads list
+  void purge_all_module_reads();
+
+  // Special handling for unnamed module, one per class loader's ModuleEntryTable
+  void create_unnamed_module(ClassLoaderData* loader_data);
+  ModuleEntry* unnamed_module()                           { return _unnamed_module; }
+
+  // Special handling for java.base
+  static ModuleEntry* javabase_module()                   { return _javabase_module; }
+  static void set_javabase_module(ModuleEntry* java_base) { _javabase_module = java_base; }
+  static bool javabase_defined()                          { return ((_javabase_module != NULL) &&
+                                                                    (_javabase_module->module() != NULL)); }
+  static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location);
+  static void patch_javabase_entries(Handle module_handle);
+
+  void print() PRODUCT_RETURN;
+  void verify();
+};
+
+#endif // SHARE_VM_CLASSFILE_MODULEENTRY_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/modules.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,964 @@
+/*
+* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#include "precompiled.hpp"
+#include "classfile/classFileParser.hpp"
+#include "classfile/classLoader.hpp"
+#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/javaAssertions.hpp"
+#include "classfile/javaClasses.hpp"
+#include "classfile/javaClasses.inline.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "classfile/modules.hpp"
+#include "classfile/packageEntry.hpp"
+#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "logging/log.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "oops/objArrayOop.inline.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/reflection.hpp"
+#include "utilities/utf8.hpp"
+
+static bool verify_module_name(char *module_name) {
+  if (module_name == NULL) return false;
+  int len = (int)strlen(module_name);
+  return (len > 0 && len <= Symbol::max_length() &&
+    UTF8::is_legal_utf8((unsigned char *)module_name, len, false) &&
+    ClassFileParser::verify_unqualified_name(module_name, len,
+    ClassFileParser::LegalModule));
+}
+
+bool Modules::verify_package_name(char *package_name) {
+  if (package_name == NULL) return false;
+  int len = (int)strlen(package_name);
+  return (len > 0 && len <= Symbol::max_length() &&
+    UTF8::is_legal_utf8((unsigned char *)package_name, len, false) &&
+    ClassFileParser::verify_unqualified_name(package_name, len,
+    ClassFileParser::LegalClass));
+}
+
+static char* get_module_name(oop module, TRAPS) {
+  oop name_oop = java_lang_reflect_Module::name(module);
+  if (name_oop == NULL) {
+    THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), "Null module name");
+  }
+  char* module_name = java_lang_String::as_utf8_string(name_oop);
+  if (!verify_module_name(module_name)) {
+    THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
+                   err_msg("Invalid module name: %s",
+                           module_name != NULL ? module_name : "NULL"));
+  }
+  return module_name;
+}
+
+static const char* get_module_version(jstring version) {
+  if (version == NULL) {
+    return NULL;
+  }
+  return java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(version));
+}
+
+static ModuleEntryTable* get_module_entry_table(Handle h_loader, TRAPS) {
+  // This code can be called during start-up, before the classLoader's classLoader data got
+  // created.  So, call register_loader() to make sure the classLoader data gets created.
+  ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL);
+  return loader_cld->modules();
+}
+
+static PackageEntryTable* get_package_entry_table(Handle h_loader, TRAPS) {
+  // This code can be called during start-up, before the classLoader's classLoader data got
+  // created.  So, call register_loader() to make sure the classLoader data gets created.
+  ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL);
+  return loader_cld->packages();
+}
+
+static ModuleEntry* get_module_entry(jobject module, TRAPS) {
+  Handle module_h(THREAD, JNIHandles::resolve(module));
+  if (!java_lang_reflect_Module::is_instance(module_h())) {
+    THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Bad module object");
+  }
+  return java_lang_reflect_Module::module_entry(module_h(), CHECK_NULL);
+}
+
+static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring package, TRAPS) {
+  ResourceMark rm(THREAD);
+  if (package == NULL) return NULL;
+  const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
+  if (package_name == NULL) return NULL;
+  TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL);
+  PackageEntryTable* package_entry_table = module_entry->loader()->packages();
+  assert(package_entry_table != NULL, "Unexpected null package entry table");
+  return package_entry_table->lookup_only(pkg_symbol);
+}
+
+static PackageEntry* get_package_entry_by_name(Symbol* package,
+                                               Handle h_loader,
+                                               TRAPS) {
+  if (package != NULL) {
+    ResourceMark rm(THREAD);
+    if (Modules::verify_package_name(package->as_C_string())) {
+      PackageEntryTable* const package_entry_table =
+        get_package_entry_table(h_loader, CHECK_NULL);
+      assert(package_entry_table != NULL, "Unexpected null package entry table");
+      return package_entry_table->lookup_only(package);
+    }
+  }
+  return NULL;
+}
+
+// Check if -Xpatch:<dirs> was specified.  If so, prepend each <dir>/module_name,
+// if it exists, to bootpath so boot loader can find the class files.  Also, if
+// using exploded modules, append <java.home>/modules/module_name, if it exists,
+// to bootpath so that its class files can be found by the boot loader.
+static void add_to_boot_loader_list(char *module_name, TRAPS) {
+  // java.base should be handled by argument parsing.
+  assert(strcmp(module_name, "java.base") != 0, "Unexpected java.base module name");
+  char file_sep = os::file_separator()[0];
+  size_t module_len = strlen(module_name);
+
+  // If -Xpatch is set then add <patch-dir>/module_name paths.
+  char** patch_dirs = Arguments::patch_dirs();
+  if (patch_dirs != NULL) {
+    int dir_count = Arguments::patch_dirs_count();
+    for (int x = 0; x < dir_count; x++) {
+      // Really shouldn't be NULL, but check can't hurt
+      if (patch_dirs[x] != NULL) {
+        size_t len = strlen(patch_dirs[x]);
+        if (len != 0) { // Ignore empty strings.
+          len = len + module_len + 2;
+          char* prefix_path = NEW_C_HEAP_ARRAY(char, len, mtInternal);
+          jio_snprintf(prefix_path, len, "%s%c%s", patch_dirs[x], file_sep, module_name);
+
+          // See if Xpatch module path exists.
+          struct stat st;
+          if ((os::stat(prefix_path, &st) != 0)) {
+            FREE_C_HEAP_ARRAY(char, prefix_path);
+          } else {
+            {
+              HandleMark hm;
+              Handle loader_lock = Handle(THREAD, SystemDictionary::system_loader_lock());
+              ObjectLocker ol(loader_lock, THREAD);
+              ClassLoader::prepend_to_list(prefix_path);
+            }
+            log_info(classload)("opened: -Xpatch %s", prefix_path);
+          }
+        }
+      }
+    }
+  }
+
+  // If "modules" jimage does not exist then assume exploded form
+  // ${java.home}/modules/<module-name>
+  char* path = NULL;
+  if (!ClassLoader::has_jimage()) {
+    const char* home = Arguments::get_java_home();
+    size_t len = strlen(home) + module_len + 32;
+    path = NEW_C_HEAP_ARRAY(char, len, mtInternal);
+    jio_snprintf(path, len, "%s%cmodules%c%s", home, file_sep, file_sep, module_name);
+    struct stat st;
+    // See if exploded module path exists.
+    if ((os::stat(path, &st) != 0)) {
+      FREE_C_HEAP_ARRAY(char, path);
+      path = NULL;
+    }
+  }
+
+  if (path != NULL) {
+    HandleMark hm;
+    Handle loader_lock = Handle(THREAD, SystemDictionary::system_loader_lock());
+    ObjectLocker ol(loader_lock, THREAD);
+
+    log_info(classload)("opened: %s", path);
+    ClassLoader::add_to_list(path);
+  }
+}
+
+bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) {
+  PackageEntry* res = get_package_entry_by_name(package, h_loader, CHECK_false);
+  return res != NULL;
+}
+
+static void define_javabase_module(jobject module, jstring version,
+                                   jstring location, jobjectArray packages, TRAPS) {
+  ResourceMark rm(THREAD);
+
+  Handle module_handle(THREAD, JNIHandles::resolve(module));
+
+  // Obtain java.base's module version
+  const char* module_version = get_module_version(version);
+  TempNewSymbol version_symbol;
+  if (module_version != NULL) {
+    version_symbol = SymbolTable::new_symbol(module_version, CHECK);
+  } else {
+    version_symbol = NULL;
+  }
+
+  // Obtain java.base's location
+  const char* module_location = NULL;
+  TempNewSymbol location_symbol = NULL;
+  if (location != NULL) {
+    module_location =
+      java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location));
+    if (module_location != NULL) {
+      location_symbol = SymbolTable::new_symbol(module_location, CHECK);
+    }
+  }
+
+  objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages));
+  objArrayHandle packages_h(THREAD, packages_oop);
+  int num_packages = (packages_h == NULL ? 0 : packages_h->length());
+
+  // Check that the list of packages has no duplicates and that the
+  // packages are syntactically ok.
+  GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages);
+  for (int x = 0; x < num_packages; x++) {
+    oop string_obj = packages_h->obj_at(x);
+
+    if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                "Bad package name for module: java.base");
+    }
+    char *package_name = java_lang_String::as_utf8_string(string_obj);
+    if (!Modules::verify_package_name(package_name)) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                err_msg("Invalid package name: %s for module: java.base", package_name));
+    }
+    Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
+    // append_if_missing() returns FALSE if entry already exists.
+    if (!pkg_list->append_if_missing(pkg_symbol)) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                err_msg("Duplicate package name: %s for module java.base",
+                        package_name));
+    }
+  }
+
+  // Validate java_base's loader is the boot loader.
+  oop loader = java_lang_reflect_Module::loader(module_handle());
+  if (loader != NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "Class loader must be the boot class loader");
+  }
+  Handle h_loader = Handle(THREAD, loader);
+
+  // Ensure the boot loader's PackageEntryTable has been created
+  PackageEntryTable* package_table = get_package_entry_table(h_loader, CHECK);
+  assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table");
+
+  // Ensure java.base's ModuleEntry has been created
+  assert(ModuleEntryTable::javabase_module() != NULL, "No ModuleEntry for java.base");
+
+  {
+    MutexLocker m1(Module_lock, THREAD);
+
+    // Verify that all java.base packages created during bootstrapping are in
+    // pkg_list.  If any are not in pkg_list, than a non-java.base class was
+    // loaded erroneously pre java.base module definition.
+    package_table->verify_javabase_packages(pkg_list);
+
+    // loop through and add any new packages for java.base
+    PackageEntry* pkg;
+    for (int x = 0; x < pkg_list->length(); x++) {
+      // Some of java.base's packages were added early in bootstrapping, ignore duplicates.
+      if (package_table->lookup_only(pkg_list->at(x)) == NULL) {
+        pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_module());
+        assert(pkg != NULL, "Unable to create a java.base package entry");
+      }
+      // Unable to have a GrowableArray of TempNewSymbol.  Must decrement the refcount of
+      // the Symbol* that was created above for each package. The refcount was incremented
+      // by SymbolTable::new_symbol and as well by the PackageEntry creation.
+      pkg_list->at(x)->decrement_refcount();
+    }
+
+    // Finish defining java.base's ModuleEntry
+    ModuleEntryTable::finalize_javabase(module_handle, version_symbol, location_symbol);
+  }
+
+  log_debug(modules)("define_javabase_module(): Definition of module: java.base,"
+                     " version: %s, location: %s, package #: %d",
+                     module_version != NULL ? module_version : "NULL",
+                     module_location != NULL ? module_location : "NULL",
+                     pkg_list->length());
+
+  // packages defined to java.base
+  for (int x = 0; x < pkg_list->length(); x++) {
+    log_trace(modules)("define_javabase_module(): creation of package %s for module java.base",
+                       (pkg_list->at(x))->as_C_string());
+  }
+
+  // Patch any previously loaded classes' module field with java.base's jlr.Module.
+  ModuleEntryTable::patch_javabase_entries(module_handle);
+}
+
+void Modules::define_module(jobject module, jstring version,
+                            jstring location, jobjectArray packages, TRAPS) {
+  ResourceMark rm(THREAD);
+
+  if (module == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object");
+  }
+  Handle module_handle(THREAD, JNIHandles::resolve(module));
+  if (!java_lang_reflect_Module::is_subclass(module_handle->klass())) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "module is not a subclass of java.lang.reflect.Module");
+  }
+
+  char* module_name = get_module_name(module_handle(), CHECK);
+  if (module_name == NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "Module name cannot be null");
+  }
+
+  // Special handling of java.base definition
+  if (strcmp(module_name, "java.base") == 0) {
+    define_javabase_module(module, version, location, packages, CHECK);
+    return;
+  }
+
+  const char* module_version = get_module_version(version);
+
+  objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages));
+  objArrayHandle packages_h(THREAD, packages_oop);
+  int num_packages = (packages_h == NULL ? 0 : packages_h->length());
+
+  // Check that the list of packages has no duplicates and that the
+  // packages are syntactically ok.
+  GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages);
+  for (int x = 0; x < num_packages; x++) {
+    oop string_obj = packages_h->obj_at(x);
+
+    if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                err_msg("Bad package name for module: %s", module_name));
+    }
+    char *package_name = java_lang_String::as_utf8_string(string_obj);
+    if (!verify_package_name(package_name)) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                err_msg("Invalid package name: %s for module: %s",
+                        package_name, module_name));
+    }
+    Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
+    // append_if_missing() returns FALSE if entry already exists.
+    if (!pkg_list->append_if_missing(pkg_symbol)) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                err_msg("Duplicate package name: %s for module %s",
+                        package_name, module_name));
+    }
+  }
+
+  oop loader = java_lang_reflect_Module::loader(module_handle());
+  // Make sure loader is not the sun.reflect.DelegatingClassLoader.
+  if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "Class loader is an invalid delegating class loader");
+  }
+  Handle h_loader = Handle(THREAD, loader);
+
+  // Check that loader is a subclass of java.lang.ClassLoader.
+  if (loader != NULL && !java_lang_ClassLoader::is_subclass(h_loader->klass())) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "Class loader is not a subclass of java.lang.ClassLoader");
+  }
+
+  ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK);
+  assert(module_table != NULL, "module entry table shouldn't be null");
+
+  // Create symbol* entry for module name.
+  TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK);
+
+  int dupl_pkg_index = -1;
+  bool dupl_modules = false;
+
+  // Create symbol* entry for module version.
+  TempNewSymbol version_symbol;
+  if (module_version != NULL) {
+    version_symbol = SymbolTable::new_symbol(module_version, CHECK);
+  } else {
+    version_symbol = NULL;
+  }
+
+  // Create symbol* entry for module location.
+  const char* module_location = NULL;
+  TempNewSymbol location_symbol = NULL;
+  if (location != NULL) {
+    module_location =
+      java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location));
+    if (module_location != NULL) {
+      location_symbol = SymbolTable::new_symbol(module_location, CHECK);
+    }
+  }
+
+  ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(h_loader());
+  assert(loader_data != NULL, "class loader data shouldn't be null");
+
+  PackageEntryTable* package_table = NULL;
+  {
+    MutexLocker ml(Module_lock, THREAD);
+
+    if (num_packages > 0) {
+      package_table = get_package_entry_table(h_loader, CHECK);
+      assert(package_table != NULL, "Missing package_table");
+
+      // Check that none of the packages exist in the class loader's package table.
+      for (int x = 0; x < pkg_list->length(); x++) {
+        if (package_table->lookup_only(pkg_list->at(x)) != NULL) {
+          // This could be because the module was already defined.  If so,
+          // report that error instead of the package error.
+          if (module_table->lookup_only(module_symbol) != NULL) {
+            dupl_modules = true;
+          } else {
+            dupl_pkg_index = x;
+          }
+          break;
+        }
+      }
+    }  // if (num_packages > 0)...
+
+    // Add the module and its packages.
+    if (!dupl_modules && dupl_pkg_index == -1) {
+      // Create the entry for this module in the class loader's module entry table.
+
+      ModuleEntry* module_entry = module_table->locked_create_entry_or_null(module_handle, module_symbol,
+                                    version_symbol, location_symbol, loader_data);
+
+      if (module_entry == NULL) {
+        dupl_modules = true;
+      } else {
+        // Add the packages.
+        assert(pkg_list->length() == 0 || package_table != NULL, "Bad package table");
+        PackageEntry* pkg;
+        for (int y = 0; y < pkg_list->length(); y++) {
+          pkg = package_table->locked_create_entry_or_null(pkg_list->at(y), module_entry);
+          assert(pkg != NULL, "Unable to create a module's package entry");
+
+          // Unable to have a GrowableArray of TempNewSymbol.  Must decrement the refcount of
+          // the Symbol* that was created above for each package. The refcount was incremented
+          // by SymbolTable::new_symbol and as well by the PackageEntry creation.
+          pkg_list->at(y)->decrement_refcount();
+        }
+
+        // Store pointer to ModuleEntry record in java.lang.reflect.Module object.
+        java_lang_reflect_Module::set_module_entry(module_handle(), module_entry);
+      }
+    }
+  }  // Release the lock
+
+  // any errors ?
+  if (dupl_modules) {
+     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+               err_msg("Module %s is already defined", module_name));
+  }
+  if (dupl_pkg_index != -1) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              err_msg("Package %s for module %s already exists for class loader",
+                      pkg_list->at(dupl_pkg_index)->as_C_string(), module_name));
+  }
+
+  if (log_is_enabled(Debug, modules)) {
+    outputStream* logst = LogHandle(modules)::debug_stream();
+    logst->print("define_module(): creation of module: %s, version: %s, location: %s, ",
+                 module_name, module_version != NULL ? module_version : "NULL",
+                 module_location != NULL ? module_location : "NULL");
+    loader_data->print_value_on(logst);
+    logst->print_cr(", package #: %d", pkg_list->length());
+    for (int y = 0; y < pkg_list->length(); y++) {
+      log_trace(modules)("define_module(): creation of package %s for module %s",
+                         (pkg_list->at(y))->as_C_string(), module_name);
+    }
+  }
+
+  if (loader == NULL && !Universe::is_module_initialized()) {
+    // Now that the module is defined, if it is in the bootloader, make sure that
+    // its classes can be found.  Check if -Xpatch:<path> was specified.  If
+    // so prepend <path>/module_name, if it exists, to bootpath.  Also, if using
+    // exploded modules, prepend <java.home>/modules/module_name, if it exists,
+    // to bootpath.
+    add_to_boot_loader_list(module_name, CHECK);
+  }
+}
+
+void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) {
+  ResourceMark rm(THREAD);
+
+  if (module == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object");
+  }
+  Handle module_handle(THREAD, JNIHandles::resolve(module));
+  if (!java_lang_reflect_Module::is_subclass(module_handle->klass())) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "module is not a subclass of java.lang.reflect.Module");
+  }
+
+  // Ensure that this is an unnamed module
+  oop name = java_lang_reflect_Module::name(module_handle());
+  if (name != NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "boot loader's unnamed module's java.lang.reflect.Module has a name");
+  }
+
+  // Validate java_base's loader is the boot loader.
+  oop loader = java_lang_reflect_Module::loader(module_handle());
+  if (loader != NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "Class loader must be the boot class loader");
+  }
+  Handle h_loader = Handle(THREAD, loader);
+
+  log_debug(modules)("set_bootloader_unnamed_module(): recording unnamed module for boot loader");
+
+  // Ensure the boot loader's PackageEntryTable has been created
+  ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK);
+
+  // Set java.lang.reflect.Module for the boot loader's unnamed module
+  ModuleEntry* unnamed_module = module_table->unnamed_module();
+  assert(unnamed_module != NULL, "boot loader's unnamed ModuleEntry not defined");
+  unnamed_module->set_module(ClassLoaderData::the_null_class_loader_data()->add_handle(module_handle));
+  // Store pointer to the ModuleEntry in the unnamed module's java.lang.reflect.Module object.
+  java_lang_reflect_Module::set_module_entry(module_handle(), unnamed_module);
+}
+
+void Modules::add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS) {
+  if (package == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(),
+              "package is null");
+  }
+  if (from_module == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(),
+              "from_module is null");
+  }
+  ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK);
+  if (from_module_entry == NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "from_module cannot be found");
+  }
+
+  // All packages in unnamed are exported by default.
+  if (!from_module_entry->is_named()) return;
+
+  ModuleEntry* to_module_entry;
+  if (to_module == NULL) {
+    to_module_entry = NULL;  // It's an unqualified export.
+  } else {
+    to_module_entry = get_module_entry(to_module, CHECK);
+    if (to_module_entry == NULL) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                "to_module is invalid");
+    }
+  }
+
+  PackageEntry *package_entry = get_package_entry(from_module_entry, package, CHECK);
+  ResourceMark rm(THREAD);
+  if (package_entry == NULL) {
+    const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              err_msg("Package %s not found in from_module %s",
+                      package_name != NULL ? package_name : "",
+                      from_module_entry->name()->as_C_string()));
+  }
+  if (package_entry->module() != from_module_entry) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              err_msg("Package: %s found in module %s, not in from_module: %s",
+                      package_entry->name()->as_C_string(),
+                      package_entry->module()->name()->as_C_string(),
+                      from_module_entry->name()->as_C_string()));
+  }
+
+  log_debug(modules)("add_module_exports(): package %s in module %s is exported to module %s",
+                     package_entry->name()->as_C_string(),
+                     from_module_entry->name()->as_C_string(),
+                     to_module_entry == NULL ? "NULL" :
+                      to_module_entry->is_named() ?
+                        to_module_entry->name()->as_C_string() : UNNAMED_MODULE);
+
+  // Do nothing if modules are the same or if package is already exported unqualifiedly.
+  if (from_module_entry != to_module_entry && !package_entry->is_unqual_exported()) {
+    package_entry->set_exported(to_module_entry);
+  }
+}
+
+
+void Modules::add_module_exports_qualified(jobject from_module, jstring package,
+                                           jobject to_module, TRAPS) {
+  if (to_module == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(),
+              "to_module is null");
+  }
+  add_module_exports(from_module, package, to_module, CHECK);
+}
+
+void Modules::add_reads_module(jobject from_module, jobject to_module, TRAPS) {
+  if (from_module == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(),
+              "from_module is null");
+  }
+
+  ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK);
+  if (from_module_entry == NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "from_module is not valid");
+  }
+
+  ModuleEntry* to_module_entry;
+  if (to_module != NULL) {
+    to_module_entry = get_module_entry(to_module, CHECK);
+    if (to_module_entry == NULL) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                "to_module is invalid");
+    }
+  } else {
+    to_module_entry = NULL;
+  }
+
+  ResourceMark rm(THREAD);
+  log_debug(modules)("add_reads_module(): Adding read from module %s to module %s",
+                     from_module_entry->is_named() ?
+                     from_module_entry->name()->as_C_string() : UNNAMED_MODULE,
+                     to_module_entry == NULL ? "all unnamed" :
+                       (to_module_entry->is_named() ?
+                        to_module_entry->name()->as_C_string() : UNNAMED_MODULE));
+
+  // if modules are the same or if from_module is unnamed then no need to add the read.
+  if (from_module_entry != to_module_entry && from_module_entry->is_named()) {
+    from_module_entry->add_read(to_module_entry);
+  }
+}
+
+jboolean Modules::can_read_module(jobject asking_module, jobject target_module, TRAPS) {
+  if (asking_module == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
+               "asking_module is null", JNI_FALSE);
+  }
+
+  ModuleEntry* asking_module_entry = get_module_entry(asking_module, CHECK_false);
+  if (asking_module_entry == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               "asking_module is invalid", JNI_FALSE);
+  }
+
+  // Calling can_read_all_unnamed() with NULL tests if a module is loose.
+  if (target_module == NULL) {
+    return asking_module_entry->can_read_all_unnamed();
+  }
+
+  ModuleEntry* target_module_entry = get_module_entry(target_module, CHECK_false);
+  if (target_module_entry == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               "target_module is invalid", JNI_FALSE);
+  }
+
+  ResourceMark rm(THREAD);
+  log_debug(modules)("can_read_module(): module %s trying to read module %s, allowed = %s",
+                     asking_module_entry->is_named() ?
+                       asking_module_entry->name()->as_C_string() : UNNAMED_MODULE,
+                     target_module_entry->is_named() ?
+                       target_module_entry->name()->as_C_string() : UNNAMED_MODULE,
+                     BOOL_TO_STR(asking_module_entry == target_module_entry ||
+                                 (asking_module_entry->can_read_all_unnamed() &&
+                                  !target_module_entry->is_named()) ||
+                                  asking_module_entry->can_read(target_module_entry)));
+
+  // Return true if:
+  // 1. the modules are the same, or
+  // 2. the asking_module is unnamed (because unnamed modules read everybody), or
+  // 3. the asking_module is loose and the target module is unnamed, or
+  // 4. if can_read() returns true.
+  if (asking_module_entry == target_module_entry ||
+      (asking_module_entry->can_read_all_unnamed() && !target_module_entry->is_named())) {
+    return true;
+  }
+  return asking_module_entry->can_read(target_module_entry);
+}
+
+jboolean Modules::is_exported_to_module(jobject from_module, jstring package,
+                                        jobject to_module, TRAPS) {
+  if (package == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
+               "package is null", JNI_FALSE);
+  }
+  if (from_module == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
+               "from_module is null", JNI_FALSE);
+  }
+  ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK_false);
+  if (from_module_entry == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               "from_module is invalid", JNI_FALSE);
+  }
+  ModuleEntry* to_module_entry;
+  if (to_module == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
+               "to_module is null", JNI_FALSE);
+  }
+  to_module_entry = get_module_entry(to_module, CHECK_false);
+  if (to_module_entry == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               "to_module is invalid", JNI_FALSE);
+  }
+
+  PackageEntry *package_entry = get_package_entry(from_module_entry, package,
+                                                  CHECK_false);
+  ResourceMark rm(THREAD);
+  if (package_entry == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               err_msg("Package not found in from_module: %s",
+                       from_module_entry->is_named() ?
+                         from_module_entry->name()->as_C_string() : UNNAMED_MODULE),
+               JNI_FALSE);
+  }
+  if (package_entry->module() != from_module_entry) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               err_msg("Package: %s found in module %s, not in from_module: %s",
+                       package_entry->name()->as_C_string(),
+                       package_entry->module()->is_named() ?
+                         package_entry->module()->name()->as_C_string() : UNNAMED_MODULE,
+                       from_module_entry->is_named() ?
+                         from_module_entry->name()->as_C_string() : UNNAMED_MODULE),
+               JNI_FALSE);
+  }
+
+  log_debug(modules)("is_exported_to_module: package %s from module %s checking"
+                     " if exported to module %s, exported? = %s",
+                     package_entry->name()->as_C_string(),
+                     from_module_entry->is_named() ?
+                       from_module_entry->name()->as_C_string() : UNNAMED_MODULE,
+                     to_module_entry->is_named() ?
+                       to_module_entry->name()->as_C_string() : UNNAMED_MODULE,
+                     BOOL_TO_STR(!from_module_entry->is_named() ||
+                       package_entry->is_unqual_exported() ||
+                       from_module_entry == to_module_entry ||
+                       package_entry->is_qexported_to(to_module_entry)));
+
+  // Return true if:
+  // 1. from_module is unnamed because unnamed modules export all their packages (by default), or
+  // 2. if the package is unqualifiedly exported, or
+  // 3. if the modules are the same, or
+  // 4. if the package is exported to to_module
+  return (!from_module_entry->is_named() ||
+          package_entry->is_unqual_exported() ||
+          from_module_entry == to_module_entry ||
+          package_entry->is_qexported_to(to_module_entry));
+}
+
+// This method is called by JFR and JNI.
+jobject Modules::get_module(jclass clazz, TRAPS) {
+  assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_module before java.base is defined");
+
+  if (clazz == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
+               "class is null", JNI_FALSE);
+  }
+  oop mirror = JNIHandles::resolve_non_null(clazz);
+  if (mirror == NULL) {
+    log_debug(modules)("get_module(): no mirror, returning NULL");
+    return NULL;
+  }
+  if (!java_lang_Class::is_instance(mirror)) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               "Invalid class", JNI_FALSE);
+  }
+
+  oop module = java_lang_Class::module(mirror);
+
+  assert(module != NULL, "java.lang.Class module field not set");
+  assert(java_lang_reflect_Module::is_subclass(module->klass()), "Module is not a java.lang.reflect.Module");
+
+  if (log_is_enabled(Debug, modules)) {
+    ResourceMark rm(THREAD);
+    outputStream* logst = LogHandle(modules)::debug_stream();
+    Klass* klass = java_lang_Class::as_Klass(mirror);
+    oop module_name = java_lang_reflect_Module::name(module);
+    if (module_name != NULL) {
+      logst->print("get_module(): module ");
+      java_lang_String::print(module_name, tty);
+    } else {
+      logst->print("get_module(): Unamed Module");
+    }
+    if (klass != NULL) {
+      logst->print_cr(" for class %s", klass->external_name());
+    } else {
+      logst->print_cr(" for primitive class");
+    }
+  }
+
+  return JNIHandles::make_local(THREAD, module);
+}
+
+
+jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRAPS) {
+  ResourceMark rm(THREAD);
+  assert(ModuleEntryTable::javabase_defined(),
+         "Attempt to call get_module_from_pkg before java.base is defined");
+
+  if (NULL == package) {
+    THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
+               "package is null", JNI_FALSE);
+  }
+  const char* package_str =
+    java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
+  if (NULL == package_str) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               "Invalid package", JNI_FALSE);
+  }
+
+  Handle h_loader (THREAD, JNIHandles::resolve(loader));
+  // Check that loader is a subclass of java.lang.ClassLoader.
+  if (loader != NULL && !java_lang_ClassLoader::is_subclass(h_loader->klass())) {
+    THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
+               "Class loader is not a subclass of java.lang.ClassLoader", JNI_FALSE);
+  }
+
+  if (strlen(package_str) == 0) {
+    // Return the unnamed module
+    ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK_NULL);
+    if (NULL == module_table) return NULL;
+    const ModuleEntry* const unnamed_module = module_table->unnamed_module();
+    return JNIHandles::make_local(THREAD, JNIHandles::resolve(unnamed_module->module()));
+
+  } else {
+    TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
+    return get_module(package_sym, h_loader, CHECK_NULL);
+  }
+  return NULL;
+}
+
+
+// This method is called by JFR and by the above method.
+jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) {
+  const PackageEntry* const pkg_entry =
+    get_package_entry_by_name(package_name, h_loader, THREAD);
+  const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL);
+
+  if (module_entry != NULL &&
+      module_entry->module() != NULL) {
+    return JNIHandles::make_local(THREAD, JNIHandles::resolve(module_entry->module()));
+  }
+
+  return NULL;
+}
+
+void Modules::add_module_package(jobject module, jstring package, TRAPS) {
+  ResourceMark rm(THREAD);
+
+  if (module == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(),
+              "module is null");
+  }
+  if (package == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(),
+              "package is null");
+  }
+  ModuleEntry* module_entry = get_module_entry(module, CHECK);
+  if (module_entry == NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "module is invalid");
+  }
+  if (!module_entry->is_named()) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "module cannot be an unnamed module");
+  }
+  char *package_name = java_lang_String::as_utf8_string(
+    JNIHandles::resolve_non_null(package));
+  if (package_name == NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad package");
+  }
+  if (!verify_package_name(package_name)) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              err_msg("Invalid package name: %s", package_name));
+  }
+
+  log_debug(modules)("add_module_package(): Adding package %s to module %s",
+                     package_name, module_entry->name()->as_C_string());
+
+  TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
+  PackageEntryTable* package_table = module_entry->loader()->packages();
+  assert(package_table != NULL, "Missing package_table");
+
+  bool pkg_exists = false;
+  {
+    MutexLocker ml(Module_lock, THREAD);
+
+    // Check that the package does not exist in the class loader's package table.
+    if (!package_table->lookup_only(pkg_symbol)) {
+      PackageEntry* pkg = package_table->locked_create_entry_or_null(pkg_symbol, module_entry);
+      assert(pkg != NULL, "Unable to create a module's package entry");
+    } else {
+      pkg_exists = true;
+    }
+  }
+  if (pkg_exists) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              err_msg("Package %s already exists for class loader", package_name));
+  }
+}
+
+// Export package in module to all unnamed modules.
+void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS) {
+  if (module == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(),
+              "module is null");
+  }
+  if (package == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(),
+              "package is null");
+  }
+  ModuleEntry* module_entry = get_module_entry(module, CHECK);
+  if (module_entry == NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "module is invalid");
+  }
+
+  if (module_entry->is_named()) { // No-op for unnamed module.
+    PackageEntry *package_entry = get_package_entry(module_entry, package, CHECK);
+    ResourceMark rm(THREAD);
+    if (package_entry == NULL) {
+      const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                err_msg("Package %s not found in module %s",
+                        package_name != NULL ? package_name : "",
+                        module_entry->name()->as_C_string()));
+    }
+    if (package_entry->module() != module_entry) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+                err_msg("Package: %s found in module %s, not in module: %s",
+                        package_entry->name()->as_C_string(),
+                        package_entry->module()->name()->as_C_string(),
+                        module_entry->name()->as_C_string()));
+    }
+
+    log_debug(modules)("add_module_exports_to_all_unnamed(): package %s in module"
+                       " %s is exported to all unnamed modules",
+                       package_entry->name()->as_C_string(),
+                       module_entry->name()->as_C_string());
+
+    // Mark package as exported to all unnamed modules, unless already
+    // unqualifiedly exported.
+    if (!package_entry->is_unqual_exported()) {
+      package_entry->set_is_exported_allUnnamed();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/modules.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,151 @@
+/*
+* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_CLASSFILE_MODULES_HPP
+#define SHARE_VM_CLASSFILE_MODULES_HPP
+
+#include "memory/allocation.hpp"
+#include "runtime/handles.hpp"
+
+class Symbol;
+
+class Modules : AllStatic {
+
+public:
+  // define_module defines a module containing the specified packages. It binds the
+  // module to its class loader by creating the ModuleEntry record in the
+  // ClassLoader's ModuleEntry table, and creates PackageEntry records in the class
+  // loader's PackageEntry table.  As in JVM_DefineClass the jstring format for all
+  // package names must use "/" and not "."
+  //
+  //  IllegalArgumentExceptions are thrown for the following :
+  // * Module's Class loader is not a subclass of java.lang.ClassLoader
+  // * Module's Class loader already has a module with that name
+  // * Module's Class loader has already defined types for any of the module's packages
+  // * Module_name is syntactically bad
+  // * Packages contains an illegal package name
+  // * Packages contains a duplicate package name
+  // * A package already exists in another module for this class loader
+  // * Module is an unnamed module
+  //  NullPointerExceptions are thrown if module is null.
+  static void define_module(jobject module, jstring version,
+                            jstring location, jobjectArray packages, TRAPS);
+
+  // Provides the java.lang.reflect.Module for the unnamed module defined
+  // to the boot loader.
+  //
+  //  IllegalArgumentExceptions are thrown for the following :
+  //  * Module has a name
+  //  * Module is not a subclass of java.lang.reflect.Module
+  //  * Module's class loader is not the boot loader
+  //  NullPointerExceptions are thrown if module is null.
+  static void set_bootloader_unnamed_module(jobject module, TRAPS);
+
+  // This either does a qualified export of package in module from_module to module
+  // to_module or, if to_module is null, does an unqualified export of package.
+  // The format for the package name must use "/' not ".".
+  //
+  // Error conditions causing IlegalArgumentException to be throw :
+  // * Module from_module does not exist
+  // * Module to_module is not null and does not exist
+  // * Package is not syntactically correct
+  // * Package is not defined for from_module's class loader
+  // * Package is not in module from_module.
+  static void add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS);
+
+  // This does a qualified export of package in module from_module to module
+  // to_module.  The format for the package name must use "/' not ".".
+  //
+  // Error conditions causing IlegalArgumentException to be throw :
+  // * Module from_module does not exist
+  // * Module to_module does not exist
+  // * Package is not syntactically correct
+  // * Package is not defined for from_module's class loader
+  // * Package is not in module from_module.
+  static void add_module_exports_qualified(jobject from_module, jstring package, jobject to_module, TRAPS);
+
+  // add_reads_module adds module to_module to the list of modules that from_module
+  // can read.  If from_module is the same as to_module then this is a no-op.
+  // If to_module is null then from_module is marked as a loose module (meaning that
+  // from_module can read all current and future unnamed  modules).
+  // An IllegalArgumentException is thrown if from_module is null or either (non-null)
+  // module does not exist.
+  static void add_reads_module(jobject from_module, jobject to_module, TRAPS);
+
+  // can_read_module returns TRUE if module asking_module can read module target_module,
+  // or if they are the same module, or if the asking_module is loose and target_module
+  // is null.
+  //
+  // Throws IllegalArgumentException if:
+  // * either asking_module or target_module is not a java.lang.reflect.Module
+  static jboolean can_read_module(jobject asking_module, jobject target_module, TRAPS);
+
+  // If package is valid then this returns TRUE if module from_module exports
+  // package to module to_module, if from_module and to_module are the same
+  // module, or if package is exported without qualification.
+  //
+  // IllegalArgumentException is throw if:
+  // * Either to_module or from_module does not exist
+  // * package is syntactically incorrect
+  // * package is not in from_module
+  static jboolean is_exported_to_module(jobject from_module, jstring package, jobject to_module, TRAPS);
+
+  // Return the java.lang.reflect.Module object for this class object.
+  static jobject get_module(jclass clazz, TRAPS);
+
+  // Return the java.lang.reflect.Module object for this class loader and package.
+  // Returns NULL if the class loader has not loaded any classes in the package.
+  // The package should contain /'s, not .'s, as in java/lang, not java.lang.
+  // NullPointerException is thrown if package is null.
+  // IllegalArgumentException is thrown if loader is neither null nor a subtype of
+  // java/lang/ClassLoader.
+  static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS);
+
+  // If package is defined by loader, return the
+  // java.lang.reflect.Module object for the module in which the package is defined.
+  // Returns NULL if package is invalid or not defined by loader.
+  static jobject get_module(Symbol* package_name, Handle h_loader, TRAPS);
+
+  // This adds package to module.
+  // It throws IllegalArgumentException if:
+  // * Module is bad
+  // * Module is unnamed
+  // * Package is not syntactically correct
+  // * Package is already defined for module's class loader.
+  static void add_module_package(jobject module, jstring package, TRAPS);
+
+  // Marks the specified package as exported to all unnamed modules.
+  // If either module or package is null then NullPointerException is thrown.
+  // If module or package is bad, or module is unnamed, or package is not in
+  // module then IllegalArgumentException is thrown.
+  static void add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS);
+
+  // Return TRUE if package_name is syntactically valid, false otherwise.
+  static bool verify_package_name(char *package_name);
+
+  // Return TRUE iff package is defined by loader
+  static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS);
+};
+
+#endif // SHARE_VM_CLASSFILE_MODULES_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/packageEntry.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "classfile/packageEntry.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/symbol.hpp"
+#include "runtime/handles.inline.hpp"
+#include "trace/traceMacros.hpp"
+#include "utilities/events.hpp"
+#include "utilities/growableArray.hpp"
+#include "utilities/hashtable.inline.hpp"
+
+// Return true if this package is exported to m.
+bool PackageEntry::is_qexported_to(ModuleEntry* m) const {
+  assert(m != NULL, "No module to lookup in this package's qualified exports list");
+  MutexLocker m1(Module_lock);
+  if (!_is_exported) {
+    return false;
+  } else if (_is_exported_allUnnamed && !m->is_named()) {
+    return true;
+  } else if (_qualified_exports == NULL) {
+    return false;
+  } else {
+    return _qualified_exports->contains(m);
+  }
+}
+
+// Add a module to the package's qualified export list.
+void PackageEntry::add_qexport(ModuleEntry* m) {
+  assert_locked_or_safepoint(Module_lock);
+  assert(_is_exported == true, "Adding a qualified export to a package that is not exported");
+  if (_qualified_exports == NULL) {
+    // Lazily create a package's qualified exports list.
+    // Initial size is small, do not anticipate export lists to be large.
+    _qualified_exports =
+      new (ResourceObj::C_HEAP, mtClass) GrowableArray<ModuleEntry*>(QUAL_EXP_SIZE, true);
+  }
+  _qualified_exports->append_if_missing(m);
+}
+
+// Set the package's exported state based on the value of the ModuleEntry.
+void PackageEntry::set_exported(ModuleEntry* m) {
+  MutexLocker m1(Module_lock);
+  if (is_unqual_exported()) {
+    // An exception could be thrown, but choose to simply ignore.
+    // Illegal to convert an unqualified exported package to be qualifiedly exported
+    return;
+  }
+
+  if (m == NULL) {
+    // NULL indicates the package is being unqualifiedly exported
+    if (_is_exported && _qualified_exports != NULL) {
+      // Legit to transition a package from being qualifiedly exported
+      // to unqualified.  Clean up the qualified lists at the next
+      // safepoint.
+      _exported_pending_delete = _qualified_exports;
+    }
+
+    // Mark package as unqualifiedly exported
+    set_unqual_exported();
+
+  } else {
+    // Add the exported module
+    _is_exported = true;
+    add_qexport(m);
+  }
+}
+
+// Remove dead module entries within the package's exported list.
+void PackageEntry::purge_qualified_exports() {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  if (_qualified_exports != NULL) {
+    // Go backwards because this removes entries that are dead.
+    int len = _qualified_exports->length();
+    for (int idx = len - 1; idx >= 0; idx--) {
+      ModuleEntry* module_idx = _qualified_exports->at(idx);
+      ClassLoaderData* cld = module_idx->loader();
+      if (cld->is_unloading()) {
+        _qualified_exports->delete_at(idx);
+      }
+    }
+  }
+}
+
+void PackageEntry::delete_qualified_exports() {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  if (_exported_pending_delete != NULL) {
+    // If a transition occurred from qualified to unqualified, the _qualified_exports
+    // field should have been NULL'ed out.
+    assert(_qualified_exports == NULL, "Package's exported pending delete, exported list should not be active");
+    delete _exported_pending_delete;
+  }
+
+  if (_qualified_exports != NULL) {
+    delete _qualified_exports;
+  }
+
+  _exported_pending_delete = NULL;
+  _qualified_exports = NULL;
+}
+
+PackageEntryTable::PackageEntryTable(int table_size)
+  : Hashtable<Symbol*, mtClass>(table_size, sizeof(PackageEntry))
+{
+}
+
+PackageEntryTable::~PackageEntryTable() {
+  assert_locked_or_safepoint(Module_lock);
+
+  // Walk through all buckets and all entries in each bucket,
+  // freeing each entry.
+  for (int i = 0; i < table_size(); ++i) {
+    for (PackageEntry* p = bucket(i); p != NULL;) {
+      PackageEntry* to_remove = p;
+      // read next before freeing.
+      p = p->next();
+
+      // Clean out the C heap allocated qualified exports list first before freeing the entry
+      to_remove->delete_qualified_exports();
+      to_remove->name()->decrement_refcount();
+
+      // Unlink from the Hashtable prior to freeing
+      unlink_entry(to_remove);
+      FREE_C_HEAP_ARRAY(char, to_remove);
+    }
+  }
+  assert(number_of_entries() == 0, "should have removed all entries");
+  assert(new_entry_free_list() == NULL, "entry present on PackageEntryTable's free list");
+  free_buckets();
+}
+
+PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, ModuleEntry* module) {
+  assert_locked_or_safepoint(Module_lock);
+  PackageEntry* entry = (PackageEntry*) NEW_C_HEAP_ARRAY(char, entry_size(), mtClass);
+
+  // Initialize everything BasicHashtable would
+  entry->set_next(NULL);
+  entry->set_hash(hash);
+  entry->set_literal(name);
+
+  TRACE_INIT_PACKAGE_ID(entry);
+
+  // Initialize fields specific to a PackageEntry
+  entry->init();
+  entry->name()->increment_refcount();
+  if (!module->is_named()) {
+    // Set the exported state to true because all packages
+    // within the unnamed module are unqualifiedly exported
+    entry->set_exported(true);
+  }
+  entry->set_module(module);
+  return entry;
+}
+
+void PackageEntryTable::add_entry(int index, PackageEntry* new_entry) {
+  assert_locked_or_safepoint(Module_lock);
+  Hashtable<Symbol*, mtClass>::add_entry(index, (HashtableEntry<Symbol*, mtClass>*)new_entry);
+}
+
+// Create package in loader's package entry table and return the entry.
+// If entry already exists, return null.  Assume Module lock was taken by caller.
+PackageEntry* PackageEntryTable::locked_create_entry_or_null(Symbol* name, ModuleEntry* module) {
+  assert_locked_or_safepoint(Module_lock);
+  // Check if package already exists.  Return NULL if it does.
+  if (lookup_only(name) != NULL) {
+    return NULL;
+  } else {
+    PackageEntry* entry = new_entry(compute_hash(name), name, module);
+    add_entry(index_for(name), entry);
+    return entry;
+  }
+}
+
+PackageEntry* PackageEntryTable::lookup(Symbol* name, ModuleEntry* module) {
+  PackageEntry* p = lookup_only(name);
+  if (p != NULL) {
+    return p;
+  } else {
+    // If not found, add to table. Grab the PackageEntryTable lock first.
+    MutexLocker ml(Module_lock);
+
+    // Since look-up was done lock-free, we need to check if another thread beat
+    // us in the race to insert the package.
+    PackageEntry* test = lookup_only(name);
+    if (test != NULL) {
+      // A race occurred and another thread introduced the package.
+      return test;
+    } else {
+      assert(module != NULL, "module should never be null");
+      PackageEntry* entry = new_entry(compute_hash(name), name, module);
+      add_entry(index_for(name), entry);
+      return entry;
+    }
+  }
+}
+
+PackageEntry* PackageEntryTable::lookup_only(Symbol* name) {
+  int index = index_for(name);
+  for (PackageEntry* p = bucket(index); p != NULL; p = p->next()) {
+    if (p->name()->fast_compare(name) == 0) {
+      return p;
+    }
+  }
+  return NULL;
+}
+
+// Called when a define module for java.base is being processed.
+// Verify the packages loaded thus far are in java.base's package list.
+void PackageEntryTable::verify_javabase_packages(GrowableArray<Symbol*> *pkg_list) {
+  for (int i = 0; i < table_size(); i++) {
+    for (PackageEntry* entry = bucket(i);
+                       entry != NULL;
+                       entry = entry->next()) {
+      ModuleEntry* m = entry->module();
+      Symbol* module_name = (m == NULL ? NULL : m->name());
+      if (module_name != NULL &&
+          (module_name->fast_compare(vmSymbols::java_base()) == 0) &&
+          !pkg_list->contains(entry->name())) {
+        ResourceMark rm;
+        vm_exit_during_initialization("A non-java.base package was loaded prior to module system initialization", entry->name()->as_C_string());
+      }
+    }
+  }
+
+}
+
+// Remove dead entries from all packages' exported list
+void PackageEntryTable::purge_all_package_exports() {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  for (int i = 0; i < table_size(); i++) {
+    for (PackageEntry* entry = bucket(i);
+                       entry != NULL;
+                       entry = entry->next()) {
+      if (entry->exported_pending_delete()) {
+        // exported list is pending deletion due to a transition
+        // from qualified to unqualified
+        entry->delete_qualified_exports();
+      } else if (entry->is_qual_exported()) {
+        entry->purge_qualified_exports();
+      }
+    }
+  }
+}
+
+#ifndef PRODUCT
+void PackageEntryTable::print() {
+  tty->print_cr("Package Entry Table (table_size=%d, entries=%d)",
+                table_size(), number_of_entries());
+  for (int i = 0; i < table_size(); i++) {
+    for (PackageEntry* probe = bucket(i);
+                       probe != NULL;
+                       probe = probe->next()) {
+      probe->print();
+    }
+  }
+}
+
+void PackageEntry::print() {
+  ResourceMark rm;
+  tty->print_cr("package entry "PTR_FORMAT" name %s module %s classpath_index "
+                INT32_FORMAT " is_exported %d is_exported_allUnnamed %d " "next "PTR_FORMAT,
+                p2i(this), name()->as_C_string(),
+                (module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE),
+                _classpath_index, _is_exported, _is_exported_allUnnamed, p2i(next()));
+}
+#endif
+
+void PackageEntryTable::verify() {
+  int element_count = 0;
+  for (int index = 0; index < table_size(); index++) {
+    for (PackageEntry* probe = bucket(index);
+                              probe != NULL;
+                              probe = probe->next()) {
+      probe->verify();
+      element_count++;
+    }
+  }
+  guarantee(number_of_entries() == element_count,
+            "Verify of Package Entry Table failed");
+  debug_only(verify_lookup_length((double)number_of_entries() / table_size()));
+}
+
+void PackageEntry::verify() {
+  guarantee(name() != NULL, "A package entry must have a corresponding symbol name.");
+}
+
+// iteration of qualified exports
+void PackageEntry::package_exports_do(ModuleClosure* const f) {
+  assert_locked_or_safepoint(Module_lock);
+  assert(f != NULL, "invariant");
+
+  if (is_qual_exported()) {
+    int qe_len = _qualified_exports->length();
+
+    for (int i = 0; i < qe_len; ++i) {
+      f->do_module(_qualified_exports->at(i));
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/packageEntry.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP
+#define SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP
+
+#include "classfile/moduleEntry.hpp"
+#include "oops/symbol.hpp"
+#include "utilities/growableArray.hpp"
+#include "utilities/hashtable.hpp"
+
+// A PackageEntry basically represents a Java package.  It contains:
+//   - Symbol* containing the package's name.
+//   - ModuleEntry* for this package's containing module.
+//   - a flag indicating if package is exported, either qualifiedly or
+//     unqualifiedly.
+//   - a flag indicating if this package is exported to all unnamed modules.
+//   - a growable array containing other module entries that this
+//     package is exported to.
+//
+// Packages that are:
+//   - not exported:        _qualified_exports = NULL  && _is_exported is false
+//   - qualified exports:   (_qualified_exports != NULL || _is_exported_allUnnamed is true) && _is_exported is true
+//   - unqualified exports: (_qualified_exports = NULL && _is_exported_allUnnamed is false) && _is_exported is true
+//
+// The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either
+// data structure.
+class PackageEntry : public HashtableEntry<Symbol*, mtClass> {
+private:
+  ModuleEntry* _module;
+  // Used to indicate for packages with classes loaded by the boot loader that
+  // a class in that package has been loaded.  And, for packages with classes
+  // loaded by the boot loader from -Xbootclasspath/a in an unnamed module, it
+  // indicates from which class path entry.
+  s2 _classpath_index;
+  bool _is_exported;
+  bool _is_exported_allUnnamed;
+  GrowableArray<ModuleEntry*>* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint
+  GrowableArray<ModuleEntry*>* _qualified_exports;
+  TRACE_DEFINE_TRACE_ID_FIELD;
+
+  // Initial size of a package entry's list of qualified exports.
+  enum {QUAL_EXP_SIZE = 43};
+
+public:
+  void init() {
+    _module = NULL;
+    _classpath_index = -1;
+    _is_exported = false;
+    _is_exported_allUnnamed = false;
+    _exported_pending_delete = NULL;
+    _qualified_exports = NULL;
+  }
+
+  // package name
+  Symbol*            name() const               { return literal(); }
+  void               set_name(Symbol* n)        { set_literal(n); }
+
+  // the module containing the package definition
+  ModuleEntry*       module() const             { return _module; }
+  void               set_module(ModuleEntry* m) { _module = m; }
+
+  // package's export state
+  bool is_exported() const { return _is_exported; } // qualifiedly or unqualifiedly exported
+  bool is_qual_exported() const {
+    return (_is_exported && (_qualified_exports != NULL || _is_exported_allUnnamed));
+  }
+  bool is_unqual_exported() const {
+    return (_is_exported && (_qualified_exports == NULL && !_is_exported_allUnnamed));
+  }
+  void set_unqual_exported() {
+    _is_exported = true;
+    _is_exported_allUnnamed = false;
+    _qualified_exports = NULL;
+  }
+  bool exported_pending_delete() const     { return (_exported_pending_delete != NULL); }
+
+  void set_exported(bool e)                { _is_exported = e; }
+  void set_exported(ModuleEntry* m);
+
+  void set_is_exported_allUnnamed() {
+    if (!is_unqual_exported()) {
+     _is_exported_allUnnamed = true;
+     _is_exported = true;
+    }
+  }
+  bool is_exported_allUnnamed() const {
+    assert(_is_exported || !_is_exported_allUnnamed,
+           "is_allUnnamed set without is_exported being set");
+    return _is_exported_allUnnamed;
+  }
+
+  void set_classpath_index(s2 classpath_index) {
+    _classpath_index = classpath_index;
+  }
+  s2 classpath_index() const { return _classpath_index; }
+
+  bool has_loaded_class() const { return _classpath_index != -1; }
+
+  // returns true if the package is defined in the unnamed module
+  bool in_unnamed_module() const  { return !_module->is_named(); }
+
+  // returns true if the package specifies m as a qualified export
+  bool is_qexported_to(ModuleEntry* m) const;
+
+  // add the module to the package's qualified exports
+  void add_qexport(ModuleEntry* m);
+
+  PackageEntry* next() const {
+    return (PackageEntry*)HashtableEntry<Symbol*, mtClass>::next();
+  }
+
+  PackageEntry** next_addr() {
+    return (PackageEntry**)HashtableEntry<Symbol*, mtClass>::next_addr();
+  }
+
+  // iteration of qualified exports
+  void package_exports_do(ModuleClosure* const f);
+
+  TRACE_DEFINE_TRACE_ID_METHODS;
+
+  // Purge dead weak references out of exported list when any given class loader is unloaded.
+  void purge_qualified_exports();
+  void delete_qualified_exports();
+
+  void print() PRODUCT_RETURN;
+  void verify();
+};
+
+// The PackageEntryTable is a Hashtable containing a list of all packages defined
+// by a particular class loader.  Each package is represented as a PackageEntry node.
+// The PackageEntryTable's lookup is lock free.
+//
+class PackageEntryTable : public Hashtable<Symbol*, mtClass> {
+  friend class VMStructs;
+public:
+  enum Constants {
+    _packagetable_entry_size = 1009  // number of entries in package entry table
+  };
+
+private:
+  PackageEntry* new_entry(unsigned int hash, Symbol* name, ModuleEntry* module);
+  void add_entry(int index, PackageEntry* new_entry);
+
+  int entry_size() const { return BasicHashtable<mtClass>::entry_size(); }
+
+  PackageEntry** bucket_addr(int i) {
+    return (PackageEntry**)Hashtable<Symbol*, mtClass>::bucket_addr(i);
+  }
+
+  static unsigned int compute_hash(Symbol* name) { return (unsigned int)(name->identity_hash()); }
+  int index_for(Symbol* name) const { return hash_to_index(compute_hash(name)); }
+
+public:
+  PackageEntryTable(int table_size);
+  ~PackageEntryTable();
+
+  PackageEntry* bucket(int i) {
+    return (PackageEntry*)Hashtable<Symbol*, mtClass>::bucket(i);
+  }
+
+  // Create package in loader's package entry table and return the entry.
+  // If entry already exists, return null.  Assume Module lock was taken by caller.
+  PackageEntry* locked_create_entry_or_null(Symbol* name, ModuleEntry* module);
+
+  // lookup Package with loader's package entry table, if not found add
+  PackageEntry* lookup(Symbol* name, ModuleEntry* module);
+
+  // Only lookup Package within loader's package entry table.  The table read is lock-free.
+  PackageEntry* lookup_only(Symbol* Package);
+
+  void verify_javabase_packages(GrowableArray<Symbol*> *pkg_list);
+
+  // purge dead weak references out of exported list
+  void purge_all_package_exports();
+
+  void print() PRODUCT_RETURN;
+  void verify();
+};
+
+#endif // SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP
--- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -77,7 +77,7 @@
   outputStream* out = LogHandle(classpath)::info_stream();
   switch (type) {
   case BOOT:
-    out->print("Expecting -Dsun.boot.class.path=%s", path);
+    out->print("Expecting BOOT path=%s", path);
     break;
   case NON_EXIST:
     out->print("Expecting that %s does not exist", path);
@@ -126,7 +126,7 @@
   switch (type) {
   case BOOT:
     if (os::file_name_strcmp(path, Arguments::get_sysclasspath()) != 0) {
-      return fail("[BOOT classpath mismatch, actual: -Dsun.boot.class.path=", Arguments::get_sysclasspath());
+      return fail("[BOOT classpath mismatch, actual =", Arguments::get_sysclasspath());
     }
     break;
   case NON_EXIST: // fall-through
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -32,6 +32,7 @@
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/klassFactory.hpp"
 #include "classfile/loaderConstraints.hpp"
+#include "classfile/packageEntry.hpp"
 #include "classfile/placeholders.hpp"
 #include "classfile/resolutionErrors.hpp"
 #include "classfile/stringTable.hpp"
@@ -51,6 +52,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/symbol.hpp"
 #include "oops/typeArrayKlass.hpp"
 #include "prims/jvmtiEnvBase.hpp"
 #include "prims/methodHandles.hpp"
@@ -171,13 +173,13 @@
 }
 
 /**
- * Returns true if the passed class loader is the extension class loader.
+ * Returns true if the passed class loader is the platform class loader.
  */
-bool SystemDictionary::is_ext_class_loader(Handle class_loader) {
+bool SystemDictionary::is_platform_class_loader(Handle class_loader) {
   if (class_loader.is_null()) {
     return false;
   }
-  return (class_loader->klass()->name() == vmSymbols::sun_misc_Launcher_ExtClassLoader());
+  return (class_loader->klass() == SystemDictionary::jdk_internal_loader_ClassLoaders_PlatformClassLoader_klass());
 }
 
 // ----------------------------------------------------------------------------
@@ -1144,6 +1146,7 @@
   const char* pkg = "java/";
   if (!HAS_PENDING_EXCEPTION &&
       !class_loader.is_null() &&
+      !SystemDictionary::is_platform_class_loader(class_loader) &&
       parsed_name != NULL &&
       !strncmp((const char*)parsed_name->bytes(), pkg, strlen(pkg))) {
     // It is illegal to define classes in the "java." package from
@@ -1236,13 +1239,88 @@
   instanceKlassHandle ik (THREAD, find_shared_class(class_name));
   // Make sure we only return the boot class for the NULL classloader.
   if (ik.not_null() &&
-      SharedClassUtil::is_shared_boot_class(ik()) && class_loader.is_null()) {
+      ik->is_shared_boot_class() && class_loader.is_null()) {
     Handle protection_domain;
     return load_shared_class(ik, class_loader, protection_domain, THREAD);
   }
   return instanceKlassHandle();
 }
 
+// Check if a shared class can be loaded by the specific classloader:
+//
+// NULL classloader:
+//   - Module class from "modules" jimage. ModuleEntry must be defined in the classloader.
+//   - Class from -Xbootclasspath/a. The class has no defined PackageEntry, or must
+//     be defined in an unnamed module.
+bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
+                                               instanceKlassHandle ik,
+                                               Handle class_loader, TRAPS) {
+  int path_index = ik->shared_classpath_index();
+  SharedClassPathEntry* ent =
+            (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+  if (!Universe::is_module_initialized()) {
+    assert(ent->is_jrt(),
+           "Loading non-bootstrap classes before the module system is initialized");
+    assert(class_loader.is_null(), "sanity");
+    return true;
+  }
+  // Get the pkg_entry from the classloader
+  TempNewSymbol pkg_name = NULL;
+  PackageEntry* pkg_entry = NULL;
+  ModuleEntry* mod_entry = NULL;
+  int length = 0;
+  ClassLoaderData* loader_data = class_loader_data(class_loader);
+  const jbyte* pkg_string = InstanceKlass::package_from_name(class_name, length);
+  if (pkg_string != NULL) {
+    pkg_name = SymbolTable::new_symbol((const char*)pkg_string,
+                                       length, CHECK_(false));
+    if (loader_data != NULL) {
+      pkg_entry = loader_data->packages()->lookup_only(pkg_name);
+    }
+    if (pkg_entry != NULL) {
+      mod_entry = pkg_entry->module();
+    }
+  }
+
+  if (class_loader.is_null()) {
+    // The NULL classloader can load archived class originated from the
+    // "modules" jimage and the -Xbootclasspath/a. For class from the
+    // "modules" jimage, the PackageEntry/ModuleEntry must be defined
+    // by the NULL classloader.
+    if (mod_entry != NULL) {
+      // PackageEntry/ModuleEntry is found in the classloader. Check if the
+      // ModuleEntry's location agrees with the archived class' origination.
+      if (ent->is_jrt() && mod_entry->location()->starts_with("jrt:")) {
+        return true; // Module class from the "module" jimage
+      }
+    }
+
+    // If the archived class is not from the "module" jimage, the class can be
+    // loaded by the NULL classloader if
+    //
+    // 1. the class is from the unamed package
+    // 2. or, the class is not from a module defined in the NULL classloader
+    // 3. or, the class is from an unamed module
+    if (!ent->is_jrt() && ik->is_shared_boot_class()) {
+      // the class is from the -Xbootclasspath/a
+      if (pkg_string == NULL ||
+          pkg_entry == NULL ||
+          pkg_entry->in_unnamed_module()) {
+        assert(mod_entry == NULL ||
+               mod_entry == loader_data->modules()->unnamed_module(),
+               "the unnamed module is not defined in the classloader");
+        return true;
+      }
+    }
+    return false;
+  } else {
+    bool res = SystemDictionaryShared::is_shared_class_visible_for_classloader(
+              ik, class_loader, pkg_string, pkg_name,
+              pkg_entry, mod_entry, CHECK_(false));
+    return res;
+  }
+}
+
 instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik,
                                                         Handle class_loader,
                                                         Handle protection_domain, TRAPS) {
@@ -1250,6 +1328,12 @@
     instanceKlassHandle nh = instanceKlassHandle(); // null Handle
     Symbol* class_name = ik->name();
 
+    bool visible = is_shared_class_visible(
+                            class_name, ik, class_loader, CHECK_(nh));
+    if (!visible) {
+      return nh;
+    }
+
     // Found the class, now load the superclass and interfaces.  If they
     // are shared, add them to the main system dictionary and reset
     // their hierarchy references (supers, subs, and interfaces).
@@ -1303,12 +1387,20 @@
     }
 
     if (log_is_enabled(Info, classload)) {
-      ik()->print_loading_log(LogLevel::Info, loader_data, NULL);
+      ik()->print_loading_log(LogLevel::Info, loader_data, NULL, NULL);
     }
     // No 'else' here as logging levels are not mutually exclusive
 
     if (log_is_enabled(Debug, classload)) {
-      ik()->print_loading_log(LogLevel::Debug, loader_data, NULL);
+      ik()->print_loading_log(LogLevel::Debug, loader_data, NULL, NULL);
+    }
+
+    // For boot loader, ensure that GetSystemPackage knows that a class in this
+    // package was loaded.
+    if (class_loader.is_null()) {
+      int path_index = ik->shared_classpath_index();
+      ResourceMark rm;
+      ClassLoader::add_package(ik->name()->as_C_string(), path_index, THREAD);
     }
 
     if (DumpLoadedClassList != NULL && classlist_file->is_open()) {
@@ -1329,7 +1421,68 @@
 
 instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
   instanceKlassHandle nh = instanceKlassHandle(); // null Handle
+
   if (class_loader.is_null()) {
+    int length = 0;
+    PackageEntry* pkg_entry = NULL;
+    bool search_only_bootloader_append = false;
+    ClassLoaderData *loader_data = class_loader_data(class_loader);
+
+    // Find the package in the boot loader's package entry table.
+    const jbyte* pkg_string = InstanceKlass::package_from_name(class_name, length);
+    if (pkg_string != NULL) {
+      TempNewSymbol pkg_name = SymbolTable::new_symbol((const char*)pkg_string, length, CHECK_(nh));
+      pkg_entry = loader_data->packages()->lookup_only(pkg_name);
+    }
+
+    // Prior to attempting to load the class, enforce the boot loader's
+    // visibility boundaries.
+    if (!Universe::is_module_initialized()) {
+      // During bootstrapping, prior to module initialization, any
+      // class attempting to be loaded must be checked against the
+      // java.base packages in the boot loader's PackageEntryTable.
+      // No class outside of java.base is allowed to be loaded during
+      // this bootstrapping window.
+      if (!DumpSharedSpaces) {
+        if (pkg_entry == NULL || pkg_entry->in_unnamed_module()) {
+          // Class is either in the unnamed package or in
+          // a named package within the unnamed module.  Either
+          // case is outside of java.base, do not attempt to
+          // load the class post java.base definition.  If
+          // java.base has not been defined, let the class load
+          // and its package will be checked later by
+          // ModuleEntryTable::verify_javabase_packages.
+          if (ModuleEntryTable::javabase_defined()) {
+            return nh;
+          }
+        } else {
+          // Check that the class' package is defined within java.base.
+          ModuleEntry* mod_entry = pkg_entry->module();
+          Symbol* mod_entry_name = mod_entry->name();
+          if (mod_entry_name->fast_compare(vmSymbols::java_base()) != 0) {
+            return nh;
+          }
+        }
+      }
+    } else {
+      assert(!DumpSharedSpaces, "Archive dumped after module system initialization");
+      // After the module system has been initialized, check if the class'
+      // package is in a module defined to the boot loader.
+      if (pkg_string == NULL || pkg_entry == NULL || pkg_entry->in_unnamed_module()) {
+        // Class is either in the unnamed package, in a named package
+        // within a module not defined to the boot loader or in a
+        // a named package within the unnamed module.  In all cases,
+        // limit visibility to search for the class only in the boot
+        // loader's append path.
+        search_only_bootloader_append = true;
+      }
+    }
+
+    // Prior to bootstrapping's module initialization, never load a class outside
+    // of the boot loader's module path
+    assert(Universe::is_module_initialized() || DumpSharedSpaces ||
+           !search_only_bootloader_append,
+           "Attempt to load a class outside of boot loader's module path");
 
     // Search the shared system dictionary for classes preloaded into the
     // shared spaces.
@@ -1344,7 +1497,7 @@
     if (k.is_null()) {
       // Use VM class loader
       PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time());
-      k = ClassLoader::load_class(class_name, CHECK_(nh));
+      k = ClassLoader::load_class(class_name, search_only_bootloader_append, CHECK_(nh));
     }
 
     // find_or_define_instance_class may return a different InstanceKlass
@@ -1669,7 +1822,7 @@
 }
 
 
-// Get the next class in the diictionary.
+// Get the next class in the dictionary.
 Klass* SystemDictionary::try_get_next_class() {
   return dictionary()->try_get_next_class();
 }
@@ -1940,6 +2093,11 @@
 
 void SystemDictionary::initialize_preloaded_classes(TRAPS) {
   assert(WK_KLASS(Object_klass) == NULL, "preloaded classes should only be initialized once");
+
+  // Create the ModuleEntry for java.base.  This call needs to be done here,
+  // after vmSymbols::initialize() is called but before any classes are pre-loaded.
+  ClassLoader::create_javabase();
+
   // Preload commonly used klasses
   WKID scan = FIRST_WKID;
   // first do Object, then String, Class
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -135,6 +135,7 @@
   do_klass(Properties_klass,                            java_util_Properties,                      Pre                 ) \
   do_klass(reflect_AccessibleObject_klass,              java_lang_reflect_AccessibleObject,        Pre                 ) \
   do_klass(reflect_Field_klass,                         java_lang_reflect_Field,                   Pre                 ) \
+  do_klass(reflect_Module_klass,                        java_lang_reflect_Module,                  Pre                 ) \
   do_klass(reflect_Parameter_klass,                     java_lang_reflect_Parameter,               Opt                 ) \
   do_klass(reflect_Method_klass,                        java_lang_reflect_Method,                  Pre                 ) \
   do_klass(reflect_Constructor_klass,                   java_lang_reflect_Constructor,             Pre                 ) \
@@ -167,15 +168,17 @@
   do_klass(StringBuffer_klass,                          java_lang_StringBuffer,                    Pre                 ) \
   do_klass(StringBuilder_klass,                         java_lang_StringBuilder,                   Pre                 ) \
   do_klass(internal_Unsafe_klass,                       jdk_internal_misc_Unsafe,                  Pre                 ) \
+  do_klass(module_Modules_klass,                        jdk_internal_module_Modules,               Pre                 ) \
                                                                                                                          \
   /* support for CDS */                                                                                                  \
   do_klass(ByteArrayInputStream_klass,                  java_io_ByteArrayInputStream,              Pre                 ) \
   do_klass(File_klass,                                  java_io_File,                              Pre                 ) \
-  do_klass(URLClassLoader_klass,                        java_net_URLClassLoader,                   Pre                 ) \
   do_klass(URL_klass,                                   java_net_URL,                              Pre                 ) \
   do_klass(Jar_Manifest_klass,                          java_util_jar_Manifest,                    Pre                 ) \
-  do_klass(sun_misc_Launcher_klass,                     sun_misc_Launcher,                         Pre                 ) \
+  do_klass(jdk_internal_loader_ClassLoaders_AppClassLoader_klass,      jdk_internal_loader_ClassLoaders_AppClassLoader,       Pre ) \
+  do_klass(jdk_internal_loader_ClassLoaders_PlatformClassLoader_klass, jdk_internal_loader_ClassLoaders_PlatformClassLoader,  Pre ) \
   do_klass(CodeSource_klass,                            java_security_CodeSource,                  Pre                 ) \
+  do_klass(ParseUtil_klass,                             sun_net_www_ParseUtil,                     Pre                 ) \
                                                                                                                          \
   do_klass(StackTraceElement_klass,                     java_lang_StackTraceElement,               Opt                 ) \
                                                                                                                          \
@@ -639,6 +642,8 @@
   static instanceKlassHandle find_or_define_instance_class(Symbol* class_name,
                                                 Handle class_loader,
                                                 instanceKlassHandle k, TRAPS);
+  static bool is_shared_class_visible(Symbol* class_name, instanceKlassHandle ik,
+                                      Handle class_loader, TRAPS);
   static instanceKlassHandle load_shared_class(instanceKlassHandle ik,
                                                Handle class_loader,
                                                Handle protection_domain,
@@ -653,7 +658,7 @@
   static instanceKlassHandle load_shared_class(Symbol* class_name,
                                                Handle class_loader,
                                                TRAPS);
-  static bool is_ext_class_loader(Handle class_loader);
+  static bool is_platform_class_loader(Handle class_loader);
 
 protected:
   static Klass* find_shared_class(Symbol* class_name);
--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -44,6 +44,16 @@
     oop class_loader = loader_data->class_loader();
     return (class_loader == NULL);
   }
+  static bool is_shared_class_visible_for_classloader(
+                                      instanceKlassHandle ik,
+                                      Handle class_loader,
+                                      const jbyte* pkg_string,
+                                      Symbol* pkg_name,
+                                      PackageEntry* pkg_entry,
+                                      ModuleEntry* mod_entry,
+                                      TRAPS) {
+    return false;
+  }
 
   static Klass* dump_time_resolve_super_or_fail(Symbol* child_name,
                                                 Symbol* class_name,
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -49,10 +49,12 @@
 // Mapping function names to values. New entries should be added below.
 
 #define VM_SYMBOLS_DO(template, do_alias)                                                         \
-  /* commonly used class names */                                                                 \
+  /* commonly used class, package, module names */                                                \
+  template(java_base,                                 "java.base")                                \
   template(java_lang_System,                          "java/lang/System")                         \
   template(java_lang_Object,                          "java/lang/Object")                         \
   template(java_lang_Class,                           "java/lang/Class")                          \
+  template(java_lang_Package,                         "java/lang/Package")                        \
   template(java_lang_String,                          "java/lang/String")                         \
   template(java_lang_StringLatin1,                    "java/lang/StringLatin1")                   \
   template(java_lang_StringUTF16,                     "java/lang/StringUTF16")                    \
@@ -87,6 +89,7 @@
   template(java_lang_reflect_Method,                  "java/lang/reflect/Method")                 \
   template(java_lang_reflect_Constructor,             "java/lang/reflect/Constructor")            \
   template(java_lang_reflect_Field,                   "java/lang/reflect/Field")                  \
+  template(java_lang_reflect_Module,                  "java/lang/reflect/Module")                 \
   template(java_lang_reflect_Parameter,               "java/lang/reflect/Parameter")              \
   template(java_lang_reflect_Array,                   "java/lang/reflect/Array")                  \
   template(java_lang_StringBuffer,                    "java/lang/StringBuffer")                   \
@@ -97,7 +100,6 @@
   template(java_security_CodeSource,                  "java/security/CodeSource")                 \
   template(java_security_ProtectionDomain,            "java/security/ProtectionDomain")           \
   template(java_security_SecureClassLoader,           "java/security/SecureClassLoader")          \
-  template(java_net_URLClassLoader,                   "java/net/URLClassLoader")                  \
   template(java_net_URL,                              "java/net/URL")                             \
   template(java_util_jar_Manifest,                    "java/util/jar/Manifest")                   \
   template(impliesCreateAccessControlContext_name,    "impliesCreateAccessControlContext")        \
@@ -116,17 +118,25 @@
   template(java_util_Hashtable,                       "java/util/Hashtable")                      \
   template(java_lang_Compiler,                        "java/lang/Compiler")                       \
   template(jdk_internal_misc_Signal,                  "jdk/internal/misc/Signal")                 \
-  template(sun_misc_Launcher,                         "sun/misc/Launcher")                        \
   template(java_lang_AssertionStatusDirectives,       "java/lang/AssertionStatusDirectives")      \
   template(getBootClassPathEntryForClass_name,        "getBootClassPathEntryForClass")            \
   template(sun_misc_PostVMInitHook,                   "sun/misc/PostVMInitHook")                  \
-  template(sun_misc_Launcher_ExtClassLoader,          "sun/misc/Launcher$ExtClassLoader")         \
+  template(sun_net_www_ParseUtil,                     "sun/net/www/ParseUtil")                    \
+                                                                                                  \
+  template(jdk_internal_loader_ClassLoaders_AppClassLoader,      "jdk/internal/loader/ClassLoaders$AppClassLoader")      \
+  template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \
                                                                                                   \
   /* Java runtime version access */                                                               \
   template(java_lang_VersionProps,                    "java/lang/VersionProps")                   \
   template(java_runtime_name_name,                    "java_runtime_name")                        \
   template(java_runtime_version_name,                 "java_runtime_version")                     \
                                                                                                   \
+  /* system initialization */                                                                     \
+  template(initPhase1_name,                           "initPhase1")                               \
+  template(initPhase2_name,                           "initPhase2")                               \
+  template(initPhase3_name,                           "initPhase3")                               \
+  template(java_lang_reflect_module_init_signature,   "(Ljava/lang/ClassLoader;Ljava/lang/String;)V") \
+                                                                                                  \
   /* class file format tags */                                                                    \
   template(tag_source_file,                           "SourceFile")                               \
   template(tag_inner_classes,                         "InnerClasses")                             \
@@ -360,7 +370,6 @@
   template(run_finalization_name,                     "runFinalization")                          \
   template(run_finalizers_on_exit_name,               "runFinalizersOnExit")                      \
   template(dispatchUncaughtException_name,            "dispatchUncaughtException")                \
-  template(initializeSystemClass_name,                "initializeSystemClass")                    \
   template(loadClass_name,                            "loadClass")                                \
   template(loadClassInternal_name,                    "loadClassInternal")                        \
   template(get_name,                                  "get")                                      \
@@ -446,14 +455,22 @@
   template(signers_name,                              "signers_name")                             \
   template(loader_data_name,                          "loader_data")                              \
   template(vmdependencies_name,                       "vmdependencies")                           \
+  template(loader_name,                               "loader")                                   \
+  template(module_name,                               "module")                                   \
+  template(getModule_name,                            "getModule")                                \
+  template(addReads_name,                             "addReads")                                 \
+  template(addReads_signature,                        "(Ljava/lang/reflect/Module;Ljava/lang/reflect/Module;)V")           \
   template(input_stream_void_signature,               "(Ljava/io/InputStream;)V")                 \
-  template(getFileURL_name,                           "getFileURL")                               \
-  template(getFileURL_signature,                      "(Ljava/io/File;)Ljava/net/URL;")           \
-  template(definePackageInternal_name,                "definePackageInternal")                    \
-  template(definePackageInternal_signature,           "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)V") \
+  template(definePackage_name,                        "definePackage")                            \
+  template(definePackage_signature,                   "(Ljava/lang/String;Ljava/lang/reflect/Module;)Ljava/lang/Package;") \
+  template(defineOrCheckPackage_name,                 "defineOrCheckPackage")                     \
+  template(defineOrCheckPackage_signature,            "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)Ljava/lang/Package;") \
+  template(fileToEncodedURL_name,                     "fileToEncodedURL")                         \
+  template(fileToEncodedURL_signature,                "(Ljava/io/File;)Ljava/net/URL;")           \
   template(getProtectionDomain_name,                  "getProtectionDomain")                      \
   template(getProtectionDomain_signature,             "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \
   template(url_code_signer_array_void_signature,      "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \
+  template(module_entry_name,                         "module_entry")                             \
                                                                                                   \
   /* non-intrinsic name/signature pairs: */                                                       \
   template(register_method_name,                      "register")                                 \
@@ -531,6 +548,7 @@
   template(void_class_signature,                      "()Ljava/lang/Class;")                                      \
   template(void_class_array_signature,                "()[Ljava/lang/Class;")                                     \
   template(void_string_signature,                     "()Ljava/lang/String;")                                     \
+  template(void_module_signature,                     "()Ljava/lang/reflect/Module;")                             \
   template(object_array_object_signature,             "([Ljava/lang/Object;)Ljava/lang/Object;")                  \
   template(object_object_array_object_signature,      "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\
   template(exception_void_signature,                  "(Ljava/lang/Exception;)V")                                 \
@@ -550,6 +568,7 @@
   template(reference_signature,                       "Ljava/lang/ref/Reference;")                                \
   template(sun_misc_Cleaner_signature,                "Lsun/misc/Cleaner;")                                       \
   template(executable_signature,                      "Ljava/lang/reflect/Executable;")                           \
+  template(module_signature,                          "Ljava/lang/reflect/Module;")                               \
   template(concurrenthashmap_signature,               "Ljava/util/concurrent/ConcurrentHashMap;")                 \
   template(String_StringBuilder_signature,            "(Ljava/lang/String;)Ljava/lang/StringBuilder;")            \
   template(int_StringBuilder_signature,               "(I)Ljava/lang/StringBuilder;")                             \
@@ -574,6 +593,9 @@
   /* used to identify class loaders handling parallel class loading */                                            \
   template(parallelCapable_name,                      "parallelLockMap")                                          \
                                                                                                                   \
+  /* used to return a class loader's unnamed module */                                                            \
+  template(unnamedModule_name,                        "unnamedModule")                                            \
+                                                                                                                  \
   /* JVM monitoring and management support */                                                                     \
   template(java_lang_StackTraceElement_array,          "[Ljava/lang/StackTraceElement;")                          \
   template(java_lang_management_ThreadState,           "java/lang/management/ThreadState")                        \
@@ -632,7 +654,10 @@
   template(addThreadDumpForSynchronizers_signature,    "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;)V")   \
                                                                                                                   \
   /* JVMTI/java.lang.instrument support and VM Attach mechanism */                                                \
+  template(jdk_internal_module_Modules,                "jdk/internal/module/Modules")                             \
   template(sun_misc_VMSupport,                         "sun/misc/VMSupport")                                      \
+  template(transformedByAgent_name,                    "transformedByAgent")                                      \
+  template(transformedByAgent_signature,               "(Ljava/lang/reflect/Module;)V")                           \
   template(appendToClassPathForInstrumentation_name,   "appendToClassPathForInstrumentation")                     \
   do_alias(appendToClassPathForInstrumentation_signature, string_void_signature)                                  \
   template(serializePropertiesToByteArray_name,        "serializePropertiesToByteArray")                          \
@@ -1063,11 +1088,6 @@
    do_name(     isCompileConstant_name,                          "isCompileConstant")                                   \
    do_alias(    isCompileConstant_signature,                      object_boolean_signature)                             \
                                                                                                                         \
-  do_class(sun_hotspot_WhiteBox,                                 "sun/hotspot/WhiteBox")                                \
-  do_intrinsic(_deoptimize,          sun_hotspot_WhiteBox,        deoptimize_name, deoptimize_signature, F_R)           \
-   do_name(     deoptimize_name,                                 "deoptimize")                                          \
-   do_alias(    deoptimize_signature,                             void_method_signature)                                \
-                                                                                                                        \
   /* unsafe memory references (there are a lot of them...) */                                                           \
   do_signature(getObject_signature,       "(Ljava/lang/Object;J)Ljava/lang/Object;")                                    \
   do_signature(putObject_signature,       "(Ljava/lang/Object;JLjava/lang/Object;)V")                                   \
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -2258,10 +2258,8 @@
               // Decrement counter at checkcast.
               BI_PROFILE_SUBTYPECHECK_FAILED(objKlass);
               ResourceMark rm(THREAD);
-              const char* objName = objKlass->external_name();
-              const char* klassName = klassOf->external_name();
               char* message = SharedRuntime::generate_class_cast_message(
-                objName, klassName);
+                objKlass, klassOf);
               VM_JAVA_ERROR(vmSymbols::java_lang_ClassCastException(), message, note_classCheck_trap);
             }
             // Profile checkcast with null_seen and receiver.
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -384,7 +384,7 @@
 
   ResourceMark rm(thread);
   char* message = SharedRuntime::generate_class_cast_message(
-    thread, obj->klass()->external_name());
+    thread, obj->klass());
 
   if (ProfileTraps) {
     note_trap(thread, Deoptimization::Reason_class_check, CHECK);
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -273,18 +273,25 @@
 // Klass resolution
 
 void LinkResolver::check_klass_accessability(KlassHandle ref_klass, KlassHandle sel_klass, TRAPS) {
-  if (!Reflection::verify_class_access(ref_klass(),
-                                       sel_klass(),
-                                       true)) {
+  Reflection::VerifyClassAccessResults vca_result =
+    Reflection::verify_class_access(ref_klass(), sel_klass(), true);
+  if (vca_result != Reflection::ACCESS_OK) {
     ResourceMark rm(THREAD);
-    Exceptions::fthrow(
-      THREAD_AND_LOCATION,
-      vmSymbols::java_lang_IllegalAccessError(),
-      "tried to access class %s from class %s",
-      sel_klass->external_name(),
-      ref_klass->external_name()
-    );
-    return;
+    char* msg = Reflection::verify_class_access_msg(ref_klass(), sel_klass(), vca_result);
+    if (msg == NULL) {
+      Exceptions::fthrow(
+        THREAD_AND_LOCATION,
+        vmSymbols::java_lang_IllegalAccessError(),
+        "failed to access class %s from class %s",
+        sel_klass->external_name(),
+        ref_klass->external_name());
+    } else {
+      // Use module specific message returned by verify_class_access_msg().
+      Exceptions::fthrow(
+        THREAD_AND_LOCATION,
+        vmSymbols::java_lang_IllegalAccessError(),
+        "%s", msg);
+    }
   }
 }
 
--- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -77,7 +77,9 @@
     resolved_klass = ObjArrayKlass::cast(resolved_klass())->bottom_klass();
   }
   if (resolved_klass->is_instance_klass()) {
-    return Reflection::verify_class_access(accessing_klass(), resolved_klass(), true);
+    Reflection::VerifyClassAccessResults result =
+      Reflection::verify_class_access(accessing_klass(), resolved_klass(), true);
+    return result == Reflection::ACCESS_OK;
   }
   return true;
 }
--- a/hotspot/src/share/vm/logging/logTag.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/logging/logTag.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -62,6 +62,7 @@
   LOG_TAG(logging) \
   LOG_TAG(marking) \
   LOG_TAG(metaspace) \
+  LOG_TAG(modules) \
   LOG_TAG(monitorinflation) \
   LOG_TAG(os) \
   LOG_TAG(phases) \
--- a/hotspot/src/share/vm/memory/filemap.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/memory/filemap.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -226,12 +226,21 @@
           SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD);
         } else {
           struct stat st;
-          if ((os::stat(name, &st) == 0) && ((st.st_mode & S_IFDIR) == S_IFDIR)) {
-            if (!os::dir_is_empty(name)) {
-              ClassLoader::exit_with_path_failure("Cannot have non-empty directory in archived classpaths", name);
+          if (os::stat(name, &st) == 0) {
+            if (cpe->is_jrt()) {
+              // it's the "modules" jimage
+              ent->_timestamp = st.st_mtime;
+              ent->_filesize = st.st_size;
+            } else if ((st.st_mode & S_IFDIR) == S_IFDIR) {
+              if (!os::dir_is_empty(name)) {
+                ClassLoader::exit_with_path_failure(
+                  "Cannot have non-empty directory in archived classpaths", name);
+              }
+              ent->_filesize = -1;
             }
-            ent->_filesize = -1;
-          } else {
+          }
+          if (ent->_filesize == 0) {
+            // unknown
             ent->_filesize = -2;
           }
         }
@@ -282,7 +291,7 @@
         fail_continue("directory is not empty: %s", name);
         ok = false;
       }
-    } else if (ent->is_jar()) {
+    } else if (ent->is_jar_or_bootimage()) {
       if (ent->_timestamp != st.st_mtime ||
           ent->_filesize != st.st_size) {
         ok = false;
@@ -291,7 +300,7 @@
                         "Timestamp mismatch" :
                         "File size mismatch");
         } else {
-          fail_continue("A jar file is not the one used while building"
+          fail_continue("A jar/jimage file is not the one used while building"
                         " the shared archive file: %s", name);
         }
       }
@@ -871,6 +880,11 @@
     return false;
   }
 
+  if (Arguments::patch_dirs() != NULL) {
+    FileMapInfo::fail_continue("The shared archive file cannot be used with -Xpatch.");
+    return false;
+  }
+
   if (_version != current_version()) {
     FileMapInfo::fail_continue("The shared archive file is the wrong version.");
     return false;
--- a/hotspot/src/share/vm/memory/filemap.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/memory/filemap.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -44,14 +44,20 @@
 class SharedClassPathEntry VALUE_OBJ_CLASS_SPEC {
 public:
   const char *_name;
-  time_t _timestamp;          // jar timestamp,  0 if is directory or other
-  long   _filesize;           // jar file size, -1 if is directory, -2 if other
-  bool is_jar() {
+  time_t _timestamp;          // jar/jimage timestamp,  0 if is directory or other
+  long   _filesize;           // jar/jimage file size, -1 if is directory, -2 if other
+
+  // The _timestamp only gets set for jar files and "modules" jimage.
+  bool is_jar_or_bootimage() {
     return _timestamp != 0;
   }
   bool is_dir() {
     return _filesize == -1;
   }
+
+  bool is_jrt() {
+    return ClassLoader::is_jrt(_name);
+  }
 };
 
 class FileMapInfo : public CHeapObj<mtInternal> {
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Wed Jul 05 21:27:52 2017 +0200
@@ -603,14 +603,7 @@
   SystemDictionary::reverse();
   SystemDictionary::copy_buckets(&md_top, md_end);
 
-  ClassLoader::verify();
-  ClassLoader::copy_package_info_buckets(&md_top, md_end);
-  ClassLoader::verify();
-
   SystemDictionary::copy_table(&md_top, md_end);
-  ClassLoader::verify();
-  ClassLoader::copy_package_info_table(&md_top, md_end);
-  ClassLoader::verify();
 
   // Write the other data to the output array.
   WriteClosure wc(md_top, md_end);
@@ -716,8 +709,7 @@
 }
 
 
-void MetaspaceShared::link_one_shared_class(Klass* obj, TRAPS) {
-  Klass* k = obj;
+void MetaspaceShared::link_one_shared_class(Klass* k, TRAPS) {
   if (k->is_instance_klass()) {
     InstanceKlass* ik = InstanceKlass::cast(k);
     // Link the class to cause the bytecodes to be rewritten and the
@@ -734,6 +726,16 @@
   }
 }
 
+void MetaspaceShared::check_shared_class_loader_type(Klass* k) {
+  if (k->is_instance_klass()) {
+    InstanceKlass* ik = InstanceKlass::cast(k);
+    u2 loader_type = ik->loader_type();
+    ResourceMark rm;
+    guarantee(loader_type != 0,
+              "Class loader type is not set for this class %s", ik->name()->as_C_string());
+  }
+}
+
 void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
   // We need to iterate because verification may cause additional classes
   // to be loaded.
@@ -765,6 +767,7 @@
 }
 
 void MetaspaceShared::prepare_for_dumping() {
+  Arguments::check_unsupported_dumping_properties();
   ClassLoader::initialize_shared_path();
   FileMapInfo::allocate_classpath_entry_table();
 }
@@ -901,7 +904,7 @@
   assert(DumpSharedSpaces, "should only be called during dumping");
   if (ik->init_state() < InstanceKlass::linked) {
     bool saved = BytecodeVerificationLocal;
-    if (!SharedClassUtil::is_shared_boot_class(ik)) {
+    if (!(ik->is_shared_boot_class())) {
       // The verification decision is based on BytecodeVerificationRemote
       // for non-system classes. Since we are using the NULL classloader
       // to load non-system classes during dumping, we need to temporarily
@@ -1089,36 +1092,14 @@
                                           number_of_entries);
   buffer += sharedDictionaryLen;
 
-  // Create the package info table using the bucket array at this spot in
-  // the misc data space.  Since the package info table is never
-  // modified, this region (of mapped pages) will be (effectively, if
-  // not explicitly) read-only.
-
-  int pkgInfoLen = *(intptr_t*)buffer;
-  buffer += sizeof(intptr_t);
-  number_of_entries = *(intptr_t*)buffer;
-  buffer += sizeof(intptr_t);
-  ClassLoader::create_package_info_table((HashtableBucket<mtClass>*)buffer, pkgInfoLen,
-                                         number_of_entries);
-  buffer += pkgInfoLen;
-  ClassLoader::verify();
-
   // The following data in the shared misc data region are the linked
   // list elements (HashtableEntry objects) for the shared dictionary
-  // and package info table.
+  // table.
 
   int len = *(intptr_t*)buffer;     // skip over shared dictionary entries
   buffer += sizeof(intptr_t);
   buffer += len;
 
-  len = *(intptr_t*)buffer;     // skip over package info table entries
-  buffer += sizeof(intptr_t);
-  buffer += len;
-
-  len = *(intptr_t*)buffer;     // skip over package info table char[] arrays.
-  buffer += sizeof(intptr_t);
-  buffer += len;
-
   intptr_t* array = (intptr_t*)buffer;
   ReadClosure rc(&array);
   serialize(&rc);
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp	Thu Mar 17 19:04:16 2016 +0000
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp	Wed Jul 05 21:27:52 2017 +0200
@@ -208,6 +208,7 @@
   static bool try_link_class(InstanceKlass* ik, TRAPS);
   static void link_one_shared_class(Klass* obj, TRAPS);
   static void check_one_shared_class(Klass* obj);
+  static void check_shared_class_loader_type(Klass* obj);
   static void link_and_cleanup_shared_classes(TRAPS);