diff --git a/.hgtags b/.hgtags
index 60b05ec4f24..001205086b5 100644
--- a/.hgtags
+++ b/.hgtags
@@ -398,3 +398,4 @@ ab2c8b03c3284fcbdd157551a66f807e3a182d9b jdk-9+152
d7034ff7f8e257e81c9f95c7785dd4eaaa3c2afc jdk-9+153
8c70d170e62c0c58b5bc3ba666bd140399b98c9c jdk-10+0
45b751afd11e6c05991cf4913c5a0ac3304fcc4e jdk-9+154
+f4aff695ffe05cfdb69d8af25a4ddc6a029754ea jdk-9+155
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index b24ec390424..3d81f131af0 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -397,3 +397,4 @@ b119012d1c2ab2570fe8718633840d0c1f1f441d jdk-9+149
ef056360ddf3977d7d2ddbeb456a4d612d19ea05 jdk-9+152
816a6d03a7c44edfbd8780110529f1bdc3964fb9 jdk-9+153
8d26916eaa21b689835ffc1c0dbf12470aa9be61 jdk-9+154
+688a3863c00ebc089ab17ee1fc46272cbbd96815 jdk-9+155
diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4
index 17c03533dd7..35e835c3994 100644
--- a/common/autoconf/basics.m4
+++ b/common/autoconf/basics.m4
@@ -746,7 +746,8 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT],
fi
# set SDKROOT too, Xcode tools will pick it up
- AC_SUBST(SDKROOT,$SYSROOT)
+ SDKROOT="$SYSROOT"
+ AC_SUBST(SDKROOT)
fi
# Prepend the extra path to the global path
@@ -831,9 +832,10 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR],
CONFIGURESUPPORT_OUTPUTDIR="$OUTPUT_ROOT/configure-support"
$MKDIR -p "$CONFIGURESUPPORT_OUTPUTDIR"
- AC_SUBST(SPEC, $OUTPUT_ROOT/spec.gmk)
- AC_SUBST(CONF_NAME, $CONF_NAME)
- AC_SUBST(OUTPUT_ROOT, $OUTPUT_ROOT)
+ SPEC="$OUTPUT_ROOT/spec.gmk"
+ AC_SUBST(SPEC)
+ AC_SUBST(CONF_NAME)
+ AC_SUBST(OUTPUT_ROOT)
AC_SUBST(CONFIGURESUPPORT_OUTPUTDIR)
# The spec.gmk file contains all variables for the make system.
diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4
index 7eafd2857d3..b7ae10542ed 100644
--- a/common/autoconf/boot-jdk.m4
+++ b/common/autoconf/boot-jdk.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -325,7 +325,6 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK],
fi
AC_MSG_CHECKING([if Boot JDK is 32 or 64 bits])
AC_MSG_RESULT([$BOOT_JDK_BITS])
- AC_SUBST(BOOT_JDK_BITS)
])
AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4
index fd77fe8c2b0..13578cfa867 100644
--- a/common/autoconf/build-performance.m4
+++ b/common/autoconf/build-performance.m4
@@ -224,7 +224,7 @@ AC_DEFUN([BPERF_SETUP_CCACHE_USAGE],
AC_MSG_ERROR([On macosx, ccache 3.2 or later is required, found $CCACHE_VERSION])
fi
fi
- if test "x$USE_PRECOMPILED_HEADER" = "x1"; then
+ if test "x$USE_PRECOMPILED_HEADER" = "xtrue"; then
HAS_BAD_CCACHE=[`$ECHO $CCACHE_VERSION | \
$GREP -e '^1.*' -e '^2.*' -e '^3\.0.*' -e '^3\.1\.[0123]$'`]
if test "x$HAS_BAD_CCACHE" != "x"; then
@@ -362,20 +362,20 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS],
[disable using precompiled headers when compiling C++ @<:@enabled@:>@])],
[ENABLE_PRECOMPH=${enable_precompiled_headers}], [ENABLE_PRECOMPH=yes])
- USE_PRECOMPILED_HEADER=1
+ USE_PRECOMPILED_HEADER=true
AC_MSG_CHECKING([If precompiled header is enabled])
if test "x$ENABLE_PRECOMPH" = xno; then
AC_MSG_RESULT([no, forced])
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
elif test "x$ICECC" != "x"; then
AC_MSG_RESULT([no, does not work effectively with icecc])
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
AC_MSG_RESULT([no, does not work with Solaris Studio])
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
AC_MSG_RESULT([no, does not work with xlc])
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
else
AC_MSG_RESULT([yes])
fi
@@ -387,7 +387,7 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS],
echo "int alfa();" > conftest.h
$CXX -x c++-header conftest.h -o conftest.hpp.gch 2>&AS_MESSAGE_LOG_FD >&AS_MESSAGE_LOG_FD
if test ! -f conftest.hpp.gch; then
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
AC_MSG_RESULT([no])
else
AC_MSG_RESULT([yes])
diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4
index e5ae8eed060..ca7f625664c 100644
--- a/common/autoconf/flags.m4
+++ b/common/autoconf/flags.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -808,7 +808,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER],
IF_FALSE: [$2CXXSTD_CXXFLAG=""])
$2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} ${$2CXXSTD_CXXFLAG}"
$2JVM_CFLAGS="${$2JVM_CFLAGS} ${$2CXXSTD_CXXFLAG}"
- AC_SUBST([$2CXXSTD_CXXFLAG])
+ AC_SUBST($2CXXSTD_CXXFLAG)
fi
if test "x$OPENJDK_TARGET_OS" = xsolaris; then
$2CFLAGS_JDK="${$2CFLAGS_JDK} -D__solaris__"
@@ -1440,18 +1440,6 @@ BASIC_DEFUN_NAMED([FLAGS_LINKER_CHECK_ARGUMENTS],
AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC],
[
- # Some Zero and Shark settings.
- # ZERO_ARCHFLAG tells the compiler which mode to build for
- case "${OPENJDK_TARGET_CPU}" in
- s390)
- ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}31"
- ;;
- *)
- ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}"
- esac
- FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$ZERO_ARCHFLAG], IF_FALSE: [ZERO_ARCHFLAG=""])
- AC_SUBST(ZERO_ARCHFLAG)
-
# Check that the compiler supports -mX (or -qX on AIX) flags
# Set COMPILER_SUPPORTS_TARGET_BITS_FLAG to 'true' if it does
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}],
@@ -1476,15 +1464,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC],
AC_MSG_ERROR([--enable-warnings-as-errors accepts no argument])
fi
- if test "x$WARNINGS_AS_ERRORS" = "xfalse"; then
- # Set legacy hotspot variable
- HOTSPOT_SET_WARNINGS_AS_ERRORS="WARNINGS_ARE_ERRORS="
- else
- HOTSPOT_SET_WARNINGS_AS_ERRORS=""
- fi
-
AC_SUBST(WARNINGS_AS_ERRORS)
- AC_SUBST(HOTSPOT_SET_WARNINGS_AS_ERRORS)
case "${TOOLCHAIN_TYPE}" in
microsoft)
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 3c0f4644798..917181abf10 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -704,7 +704,6 @@ FIXPATH_DETACH_FLAG
FIXPATH
BUILD_GTEST
ENABLE_AOT
-INCLUDE_DTRACE
GCOV_ENABLED
ZIP_EXTERNAL_DEBUG_SYMBOLS
COPY_DEBUG_SYMBOLS
@@ -712,10 +711,8 @@ COMPILE_WITH_DEBUG_SYMBOLS
CFLAGS_WARNINGS_ARE_ERRORS
BUILD_CC_DISABLE_WARNING_PREFIX
DISABLE_WARNING_PREFIX
-HOTSPOT_SET_WARNINGS_AS_ERRORS
WARNINGS_AS_ERRORS
COMPILER_SUPPORTS_TARGET_BITS_FLAG
-ZERO_ARCHFLAG
LDFLAGS_TESTEXE
LDFLAGS_TESTLIB
CXXFLAGS_TESTEXE
@@ -884,7 +881,6 @@ BUILD_JDK
CREATE_BUILDJDK
JLINK
JMOD
-BOOT_JDK_BITS
JAVAC_FLAGS
BOOT_JDK_MODULAR
BOOT_JDK_SOURCETARGET
@@ -974,15 +970,12 @@ CANONICAL_TOPDIR
ORIGINAL_TOPDIR
TOPDIR
PATH_SEP
-ZERO_ARCHDEF
HOTSPOT_BUILD_CPU_DEFINE
HOTSPOT_BUILD_CPU_ARCH
HOTSPOT_BUILD_CPU
HOTSPOT_BUILD_OS_TYPE
HOTSPOT_BUILD_OS
OPENJDK_BUILD_BUNDLE_PLATFORM
-OPENJDK_BUILD_CPU_BUNDLE
-OPENJDK_BUILD_OS_BUNDLE
OPENJDK_BUILD_OS_EXPORT_DIR
OPENJDK_BUILD_CPU_OSARCH
OPENJDK_BUILD_CPU_ISADIR
@@ -994,10 +987,7 @@ HOTSPOT_TARGET_CPU
HOTSPOT_TARGET_OS_TYPE
HOTSPOT_TARGET_OS
DEFINE_CROSS_COMPILE_ARCH
-LP64
OPENJDK_TARGET_BUNDLE_PLATFORM
-OPENJDK_TARGET_CPU_BUNDLE
-OPENJDK_TARGET_OS_BUNDLE
OPENJDK_TARGET_OS_EXPORT_DIR
OPENJDK_TARGET_CPU_OSARCH
OPENJDK_TARGET_CPU_ISADIR
@@ -3818,7 +3808,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
# ... then the rest
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -3998,7 +3988,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -4273,7 +4263,7 @@ pkgadd_help() {
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -4561,7 +4551,7 @@ VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom"
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -4841,7 +4831,7 @@ VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom"
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -5180,7 +5170,7 @@ VS_SDK_PLATFORM_NAME_2013=
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1485508515
+DATE_WHEN_GENERATED=1486175373
###############################################################################
#
@@ -15936,18 +15926,14 @@ $as_echo "$COMPILE_TYPE" >&6; }
OPENJDK_TARGET_BUNDLE_PLATFORM="${OPENJDK_TARGET_OS_BUNDLE}-${OPENJDK_TARGET_CPU_BUNDLE}"
-
-
if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
- A_LP64="LP64:="
# -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in
- # unpack200.exe
+ # unpack200.exe. This variable is used in
+ # FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER.
if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xmacosx; then
OPENJDK_TARGET_ADD_LP64="-D_LP64=1"
fi
fi
- LP64=$A_LP64
-
if test "x$COMPILE_TYPE" = "xcross"; then
# FIXME: ... or should this include reduced builds..?
@@ -16092,18 +16078,14 @@ $as_echo "$COMPILE_TYPE" >&6; }
OPENJDK_BUILD_BUNDLE_PLATFORM="${OPENJDK_BUILD_OS_BUNDLE}-${OPENJDK_BUILD_CPU_BUNDLE}"
-
-
if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then
- A_LP64="LP64:="
# -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in
- # unpack200.exe
+ # unpack200.exe. This variable is used in
+ # FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER.
if test "x$OPENJDK_BUILD_OS" = xlinux || test "x$OPENJDK_BUILD_OS" = xmacosx; then
OPENJDK_BUILD_ADD_LP64="-D_LP64=1"
fi
fi
- LP64=$A_LP64
-
if test "x$COMPILE_TYPE" = "xcross"; then
# FIXME: ... or should this include reduced builds..?
@@ -16173,12 +16155,6 @@ $as_echo "$COMPILE_TYPE" >&6; }
- # ZERO_ARCHDEF is used to enable architecture-specific code.
- # This is used in legacy hotspot build.
- ZERO_ARCHDEF="$HOTSPOT_TARGET_CPU_DEFINE"
-
-
-
# Continue setting up basic stuff. Most remaining code require fundamental tools.
@@ -17280,7 +17256,7 @@ $as_echo "$as_me: WARNING: Both SYSROOT and --with-sdk-name are set, only SYSROO
fi
# set SDKROOT too, Xcode tools will pick it up
- SDKROOT=$SYSROOT
+ SDKROOT="$SYSROOT"
fi
@@ -17528,11 +17504,9 @@ $as_echo "$as_me: The path of OUTPUT_ROOT, which resolves as \"$path\", is inval
CONFIGURESUPPORT_OUTPUTDIR="$OUTPUT_ROOT/configure-support"
$MKDIR -p "$CONFIGURESUPPORT_OUTPUTDIR"
- SPEC=$OUTPUT_ROOT/spec.gmk
+ SPEC="$OUTPUT_ROOT/spec.gmk"
- CONF_NAME=$CONF_NAME
- OUTPUT_ROOT=$OUTPUT_ROOT
@@ -30730,7 +30704,6 @@ $as_echo "$BOOT_JDK_BITS" >&6; }
-
# Check whether --with-build-jdk was given.
if test "${with_build_jdk+set}" = set; then :
withval=$with_build_jdk;
@@ -51480,282 +51453,6 @@ OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${OPENJDK_BUILD_JA
- # Some Zero and Shark settings.
- # ZERO_ARCHFLAG tells the compiler which mode to build for
- case "${OPENJDK_TARGET_CPU}" in
- s390)
- ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}31"
- ;;
- *)
- ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}"
- esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- # Execute function body
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- # Execute function body
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the C compiler supports \"$ZERO_ARCHFLAG\"" >&5
-$as_echo_n "checking if the C compiler supports \"$ZERO_ARCHFLAG\"... " >&6; }
- supports=yes
-
- saved_cflags="$CFLAGS"
- CFLAGS="$CFLAGS $ZERO_ARCHFLAG"
- ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-int i;
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-else
- supports=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
- CFLAGS="$saved_cflags"
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5
-$as_echo "$supports" >&6; }
- if test "x$supports" = "xyes" ; then
- :
- C_COMP_SUPPORTS="yes"
- else
- :
- C_COMP_SUPPORTS="no"
- fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- # Execute function body
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the C++ compiler supports \"$ZERO_ARCHFLAG\"" >&5
-$as_echo_n "checking if the C++ compiler supports \"$ZERO_ARCHFLAG\"... " >&6; }
- supports=yes
-
- saved_cxxflags="$CXXFLAGS"
- CXXFLAGS="$CXXFLAG $ZERO_ARCHFLAG"
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-int i;
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-
-else
- supports=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
- CXXFLAGS="$saved_cxxflags"
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5
-$as_echo "$supports" >&6; }
- if test "x$supports" = "xyes" ; then
- :
- CXX_COMP_SUPPORTS="yes"
- else
- :
- CXX_COMP_SUPPORTS="no"
- fi
-
-
-
-
-
-
-
-
-
-
-
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if both compilers support \"$ZERO_ARCHFLAG\"" >&5
-$as_echo_n "checking if both compilers support \"$ZERO_ARCHFLAG\"... " >&6; }
- supports=no
- if test "x$C_COMP_SUPPORTS" = "xyes" -a "x$CXX_COMP_SUPPORTS" = "xyes"; then supports=yes; fi
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5
-$as_echo "$supports" >&6; }
- if test "x$supports" = "xyes" ; then
- :
-
- else
- :
- ZERO_ARCHFLAG=""
- fi
-
-
-
-
-
-
-
-
# Check that the compiler supports -mX (or -qX on AIX) flags
# Set COMPILER_SUPPORTS_TARGET_BITS_FLAG to 'true' if it does
@@ -52054,14 +51751,6 @@ $as_echo "yes (default)" >&6; }
as_fn_error $? "--enable-warnings-as-errors accepts no argument" "$LINENO" 5
fi
- if test "x$WARNINGS_AS_ERRORS" = "xfalse"; then
- # Set legacy hotspot variable
- HOTSPOT_SET_WARNINGS_AS_ERRORS="WARNINGS_ARE_ERRORS="
- else
- HOTSPOT_SET_WARNINGS_AS_ERRORS=""
- fi
-
-
case "${TOOLCHAIN_TYPE}" in
@@ -52916,7 +52605,6 @@ $as_echo "yes, dependencies present" >&6; }
fi
-
# Check whether --enable-aot was given.
if test "${enable_aot+set}" = set; then :
enableval=$enable_aot;
@@ -63694,12 +63382,14 @@ $as_echo_n "checking for which libpng to use... " >&6; }
DEFAULT_LIBPNG=bundled
# if user didn't specify, use DEFAULT_LIBPNG
if test "x${with_libpng}" = "x"; then
- with_libpng=${DEFAULT_LIBPNG}
+ with_libpng=${DEFAULT_LIBPNG}
fi
if test "x${with_libpng}" = "xbundled"; then
- USE_EXTERNAL_LIBPNG=false
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5
+ USE_EXTERNAL_LIBPNG=false
+ PNG_CFLAGS=""
+ PNG_LIBS=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5
$as_echo "bundled" >&6; }
elif test "x${with_libpng}" = "xsystem"; then
@@ -63759,33 +63449,36 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- LIBPNG_FOUND=no
+ LIBPNG_FOUND=no
elif test $pkg_failed = untried; then
- LIBPNG_FOUND=no
+ LIBPNG_FOUND=no
else
PNG_CFLAGS=$pkg_cv_PNG_CFLAGS
PNG_LIBS=$pkg_cv_PNG_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- LIBPNG_FOUND=yes
+ LIBPNG_FOUND=yes
fi
- if test "x${LIBPNG_FOUND}" = "xyes"; then
- USE_EXTERNAL_LIBPNG=true
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: system" >&5
+ if test "x${LIBPNG_FOUND}" = "xyes"; then
+ # PKG_CHECK_MODULES will set PNG_CFLAGS and PNG_LIBS
+ USE_EXTERNAL_LIBPNG=true
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: system" >&5
$as_echo "system" >&6; }
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: system not found" >&5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: system not found" >&5
$as_echo "system not found" >&6; }
- as_fn_error $? "--with-libpng=system specified, but no libpng found!" "$LINENO" 5
- fi
+ as_fn_error $? "--with-libpng=system specified, but no libpng found!" "$LINENO" 5
+ fi
else
- as_fn_error $? "Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'" "$LINENO" 5
+ as_fn_error $? "Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'" "$LINENO" 5
fi
+
+
# Check whether --with-zlib was given.
if test "${with_zlib+set}" = set; then :
withval=$with_zlib;
@@ -63888,11 +63581,13 @@ $as_echo_n "checking for which lcms to use... " >&6; }
DEFAULT_LCMS=bundled
# If user didn't specify, use DEFAULT_LCMS
if test "x${with_lcms}" = "x"; then
- with_lcms=${DEFAULT_LCMS}
+ with_lcms=${DEFAULT_LCMS}
fi
if test "x${with_lcms}" = "xbundled"; then
USE_EXTERNAL_LCMS=false
+ LCMS_CFLAGS=""
+ LCMS_LIBS=""
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5
$as_echo "bundled" >&6; }
elif test "x${with_lcms}" = "xsystem"; then
@@ -63966,6 +63661,7 @@ $as_echo "yes" >&6; }
LCMS_FOUND=yes
fi
if test "x${LCMS_FOUND}" = "xyes"; then
+ # PKG_CHECK_MODULES will set LCMS_CFLAGS and LCMS_LIBS
USE_EXTERNAL_LCMS=true
else
as_fn_error $? "--with-lcms=system specified, but no lcms found!" "$LINENO" 5
@@ -63984,6 +63680,8 @@ fi
+
+
# Setup libm (the maths library)
if test "x$OPENJDK_TARGET_OS" != "xwindows"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5
@@ -64768,11 +64466,11 @@ fi
$as_echo_n "checking if elliptic curve crypto implementation is present... " >&6; }
if test -d "${SRC_ROOT}/jdk/src/jdk.crypto.ec/share/native/libsunec/impl"; then
- ENABLE_INTREE_EC=yes
+ ENABLE_INTREE_EC=true
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
- ENABLE_INTREE_EC=no
+ ENABLE_INTREE_EC=false
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
@@ -66139,25 +65837,25 @@ else
fi
- USE_PRECOMPILED_HEADER=1
+ USE_PRECOMPILED_HEADER=true
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking If precompiled header is enabled" >&5
$as_echo_n "checking If precompiled header is enabled... " >&6; }
if test "x$ENABLE_PRECOMPH" = xno; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5
$as_echo "no, forced" >&6; }
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
elif test "x$ICECC" != "x"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no, does not work effectively with icecc" >&5
$as_echo "no, does not work effectively with icecc" >&6; }
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no, does not work with Solaris Studio" >&5
$as_echo "no, does not work with Solaris Studio" >&6; }
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no, does not work with xlc" >&5
$as_echo "no, does not work with xlc" >&6; }
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
@@ -66171,7 +65869,7 @@ $as_echo_n "checking that precompiled headers work... " >&6; }
echo "int alfa();" > conftest.h
$CXX -x c++-header conftest.h -o conftest.hpp.gch 2>&5 >&5
if test ! -f conftest.hpp.gch; then
- USE_PRECOMPILED_HEADER=0
+ USE_PRECOMPILED_HEADER=false
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
else
@@ -66458,7 +66156,7 @@ $as_echo "$as_me: WARNING: --with-ccache-dir has no meaning when ccache is not e
as_fn_error $? "On macosx, ccache 3.2 or later is required, found $CCACHE_VERSION" "$LINENO" 5
fi
fi
- if test "x$USE_PRECOMPILED_HEADER" = "x1"; then
+ if test "x$USE_PRECOMPILED_HEADER" = "xtrue"; then
HAS_BAD_CCACHE=`$ECHO $CCACHE_VERSION | \
$GREP -e '^1.*' -e '^2.*' -e '^3\.0.*' -e '^3\.1\.[0123]$'`
if test "x$HAS_BAD_CCACHE" != "x"; then
diff --git a/common/autoconf/hotspot.m4 b/common/autoconf/hotspot.m4
index 79eb26c96c9..b295b015a9f 100644
--- a/common/autoconf/hotspot.m4
+++ b/common/autoconf/hotspot.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -189,7 +189,6 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_DTRACE],
else
AC_MSG_ERROR([Invalid value for --enable-dtrace: $enable_dtrace])
fi
- AC_SUBST(INCLUDE_DTRACE)
])
################################################################################
diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4
index 2c21000845b..bb2a49f4980 100644
--- a/common/autoconf/jdk-options.m4
+++ b/common/autoconf/jdk-options.m4
@@ -210,10 +210,10 @@ AC_DEFUN_ONCE([JDKOPT_DETECT_INTREE_EC],
AC_MSG_CHECKING([if elliptic curve crypto implementation is present])
if test -d "${SRC_ROOT}/jdk/src/jdk.crypto.ec/share/native/libsunec/impl"; then
- ENABLE_INTREE_EC=yes
+ ENABLE_INTREE_EC=true
AC_MSG_RESULT([yes])
else
- ENABLE_INTREE_EC=no
+ ENABLE_INTREE_EC=false
AC_MSG_RESULT([no])
fi
@@ -479,5 +479,5 @@ AC_DEFUN_ONCE([JDKOPT_ENABLE_DISABLE_GENERATE_CLASSLIST],
AC_MSG_ERROR([Invalid value for --enable-generate-classlist: $enable_generate_classlist])
fi
- AC_SUBST([ENABLE_GENERATE_CLASSLIST])
+ AC_SUBST(ENABLE_GENERATE_CLASSLIST)
])
diff --git a/common/autoconf/lib-bundled.m4 b/common/autoconf/lib-bundled.m4
index 218d3f87adf..92b9438014b 100644
--- a/common/autoconf/lib-bundled.m4
+++ b/common/autoconf/lib-bundled.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -119,28 +119,31 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBPNG],
DEFAULT_LIBPNG=bundled
# if user didn't specify, use DEFAULT_LIBPNG
if test "x${with_libpng}" = "x"; then
- with_libpng=${DEFAULT_LIBPNG}
+ with_libpng=${DEFAULT_LIBPNG}
fi
if test "x${with_libpng}" = "xbundled"; then
- USE_EXTERNAL_LIBPNG=false
- AC_MSG_RESULT([bundled])
+ USE_EXTERNAL_LIBPNG=false
+ PNG_CFLAGS=""
+ PNG_LIBS=""
+ AC_MSG_RESULT([bundled])
elif test "x${with_libpng}" = "xsystem"; then
- PKG_CHECK_MODULES(PNG, libpng,
- [ LIBPNG_FOUND=yes ],
- [ LIBPNG_FOUND=no ])
- if test "x${LIBPNG_FOUND}" = "xyes"; then
- USE_EXTERNAL_LIBPNG=true
- AC_MSG_RESULT([system])
- else
- AC_MSG_RESULT([system not found])
- AC_MSG_ERROR([--with-libpng=system specified, but no libpng found!])
- fi
+ PKG_CHECK_MODULES(PNG, libpng, [LIBPNG_FOUND=yes], [LIBPNG_FOUND=no])
+ if test "x${LIBPNG_FOUND}" = "xyes"; then
+ # PKG_CHECK_MODULES will set PNG_CFLAGS and PNG_LIBS
+ USE_EXTERNAL_LIBPNG=true
+ AC_MSG_RESULT([system])
+ else
+ AC_MSG_RESULT([system not found])
+ AC_MSG_ERROR([--with-libpng=system specified, but no libpng found!])
+ fi
else
- AC_MSG_ERROR([Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'])
+ AC_MSG_ERROR([Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'])
fi
AC_SUBST(USE_EXTERNAL_LIBPNG)
+ AC_SUBST(PNG_CFLAGS)
+ AC_SUBST(PNG_LIBS)
])
################################################################################
@@ -204,16 +207,19 @@ AC_DEFUN_ONCE([LIB_SETUP_LCMS],
DEFAULT_LCMS=bundled
# If user didn't specify, use DEFAULT_LCMS
if test "x${with_lcms}" = "x"; then
- with_lcms=${DEFAULT_LCMS}
+ with_lcms=${DEFAULT_LCMS}
fi
if test "x${with_lcms}" = "xbundled"; then
USE_EXTERNAL_LCMS=false
+ LCMS_CFLAGS=""
+ LCMS_LIBS=""
AC_MSG_RESULT([bundled])
elif test "x${with_lcms}" = "xsystem"; then
AC_MSG_RESULT([system])
PKG_CHECK_MODULES([LCMS], [lcms2], [LCMS_FOUND=yes], [LCMS_FOUND=no])
if test "x${LCMS_FOUND}" = "xyes"; then
+ # PKG_CHECK_MODULES will set LCMS_CFLAGS and LCMS_LIBS
USE_EXTERNAL_LCMS=true
else
AC_MSG_ERROR([--with-lcms=system specified, but no lcms found!])
@@ -223,4 +229,6 @@ AC_DEFUN_ONCE([LIB_SETUP_LCMS],
fi
AC_SUBST(USE_EXTERNAL_LCMS)
+ AC_SUBST(LCMS_CFLAGS)
+ AC_SUBST(LCMS_LIBS)
])
diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4
index 5217ca32e3e..61010279a0e 100644
--- a/common/autoconf/platform.m4
+++ b/common/autoconf/platform.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -276,12 +276,6 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS],
[
PLATFORM_SETUP_LEGACY_VARS_HELPER([TARGET])
PLATFORM_SETUP_LEGACY_VARS_HELPER([BUILD])
-
- # ZERO_ARCHDEF is used to enable architecture-specific code.
- # This is used in legacy hotspot build.
- ZERO_ARCHDEF="$HOTSPOT_TARGET_CPU_DEFINE"
- AC_SUBST(ZERO_ARCHDEF)
-
])
# $1 - Either TARGET or BUILD to setup the variables for.
@@ -360,19 +354,16 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER],
OPENJDK_$1_CPU_BUNDLE="$OPENJDK_$1_CPU"
fi
OPENJDK_$1_BUNDLE_PLATFORM="${OPENJDK_$1_OS_BUNDLE}-${OPENJDK_$1_CPU_BUNDLE}"
- AC_SUBST(OPENJDK_$1_OS_BUNDLE)
- AC_SUBST(OPENJDK_$1_CPU_BUNDLE)
AC_SUBST(OPENJDK_$1_BUNDLE_PLATFORM)
if test "x$OPENJDK_$1_CPU_BITS" = x64; then
- A_LP64="LP64:="
# -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in
- # unpack200.exe
+ # unpack200.exe. This variable is used in
+ # FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER.
if test "x$OPENJDK_$1_OS" = xlinux || test "x$OPENJDK_$1_OS" = xmacosx; then
OPENJDK_$1_ADD_LP64="-D_LP64=1"
fi
fi
- AC_SUBST(LP64,$A_LP64)
if test "x$COMPILE_TYPE" = "xcross"; then
# FIXME: ... or should this include reduced builds..?
diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in
index 471f9096e01..bb6d2209c41 100644
--- a/common/autoconf/spec.gmk.in
+++ b/common/autoconf/spec.gmk.in
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -87,9 +87,8 @@ HOTSPOT_TARGET_CPU := @HOTSPOT_TARGET_CPU@
HOTSPOT_TARGET_CPU_ARCH := @HOTSPOT_TARGET_CPU_ARCH@
HOTSPOT_TARGET_CPU_DEFINE := @HOTSPOT_TARGET_CPU_DEFINE@
-OPENJDK_TARGET_CPU_BUNDLE:=@OPENJDK_TARGET_CPU_BUNDLE@
-OPENJDK_TARGET_OS_BUNDLE:=@OPENJDK_TARGET_OS_BUNDLE@
OPENJDK_TARGET_BUNDLE_PLATFORM:=@OPENJDK_TARGET_BUNDLE_PLATFORM@
+JDK_ARCH_ABI_PROP_NAME := @JDK_ARCH_ABI_PROP_NAME@
# We are building on this build system.
# When not cross-compiling, it is the same as the target.
@@ -683,8 +682,7 @@ TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@
# Build setup
ENABLE_AOT:=@ENABLE_AOT@
-ENABLE_JFR=@ENABLE_JFR@
-ENABLE_INTREE_EC=@ENABLE_INTREE_EC@
+ENABLE_INTREE_EC:=@ENABLE_INTREE_EC@
USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@
USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@
USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@
diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh
index 3007d3e8860..5d4f8eb7156 100644
--- a/common/bin/hgforest.sh
+++ b/common/bin/hgforest.sh
@@ -309,8 +309,8 @@ if [ "${command}" = "serve" ] ; then
echo "serving root repo ${serving}" > ${status_output}
- echo "hg${global_opts} serve" > ${status_output}
- (PYTHONUNBUFFERED=true hg${global_opts} serve -A ${status_output} -E ${status_output} --pid-file ${tmp}/serve.pid --web-conf ${tmp}/serve.web-conf; echo "$?" > ${tmp}/serve.pid.rc ) 2>&1 &
+ echo "hg${global_opts} serve ${@}" > ${status_output}
+ (PYTHONUNBUFFERED=true hg${global_opts} serve -A ${status_output} -E ${status_output} --pid-file ${tmp}/serve.pid --web-conf ${tmp}/serve.web-conf "${@}"; echo "$?" > ${tmp}/serve.pid.rc ) 2>&1 &
) 2>&1 | sed -e "s@^@serve: @" > ${status_output}
) &
else
diff --git a/common/bin/unshuffle_list.txt b/common/bin/unshuffle_list.txt
index a217a8f01f8..e5fe5af121d 100644
--- a/common/bin/unshuffle_list.txt
+++ b/common/bin/unshuffle_list.txt
@@ -60,7 +60,7 @@ jaxp/src/java.xml/share/classes/org/xml/sax : jaxp/src/org/xml/sax
jaxws/src/java.activation/share/classes/com/sun/activation/registries : jaxws/src/share/jaf_classes/com/sun/activation/registries
jaxws/src/java.activation/share/classes/javax/activation : jaxws/src/share/jaf_classes/javax/activation
jaxws/src/java.activation/share/classes/META-INF : jaxws/src/share/jaf_classes/META-INF
-jaxws/src/java.annotations.common/share/classes/javax/annotation : jaxws/src/share/jaxws_classes/javax/annotation
+jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation : jaxws/src/share/jaxws_classes/javax/annotation
jaxws/src/java.xml.bind/share/classes/com/sun/istack/internal : jaxws/src/share/jaxws_classes/com/sun/istack/internal
jaxws/src/java.xml.bind/share/classes/com/sun/istack/internal/localization : jaxws/src/share/jaxws_classes/com/sun/istack/internal/localization
jaxws/src/java.xml.bind/share/classes/com/sun/istack/internal/logging/Logger.java : jaxws/src/share/jaxws_classes/com/sun/istack/internal/logging/Logger.java
@@ -1163,9 +1163,6 @@ jdk/src/java.management/share/classes/mgmt-overview.html : jdk/src/share/classes
jdk/src/java.management/share/classes/sun/management/counter : jdk/src/share/classes/sun/management/counter
jdk/src/java.management/share/classes/sun/management/counter/perf : jdk/src/share/classes/sun/management/counter/perf
jdk/src/java.management/share/classes/sun/management : jdk/src/share/classes/sun/management
-jdk/src/java.management/share/classes/sun/management/jdp : jdk/src/share/classes/sun/management/jdp
-jdk/src/java.management/share/classes/sun/management/jmxremote : jdk/src/share/classes/sun/management/jmxremote
-jdk/src/java.management/share/classes/sun/management/resources : jdk/src/share/classes/sun/management/resources
jdk/src/java.management/share/conf : jdk/src/share/lib/management
jdk/src/java.management/share/native/include/jmm.h : jdk/src/share/javavm/export/jmm.h
jdk/src/java.management/share/native/libmanagement : jdk/src/share/native/sun/management
@@ -1173,6 +1170,11 @@ jdk/src/java.management/unix/classes/sun/management : jdk/src/solaris/classes/su
jdk/src/java.management/unix/native/libmanagement : jdk/src/solaris/native/sun/management
jdk/src/java.management/windows/classes/sun/management : jdk/src/windows/classes/sun/management
jdk/src/java.management/windows/native/libmanagement : jdk/src/windows/native/sun/management
+jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/ProxyRef.java : jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java
+jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/RMIExporter.java : jdk/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java
+jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/Unmarshal.java : jdk/src/share/classes/com/sun/jmx/remote/internal/Unmarshal.java
+jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/protocol/rmi : jdk/src/share/classes/com/sun/jmx/remote/protocol/rmi
+jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi : jdk/src/share/classes/javax/management/remote/rmi
jdk/src/java.naming/share/classes/com/sun/jndi/ldap/ext : jdk/src/share/classes/com/sun/jndi/ldap/ext
jdk/src/java.naming/share/classes/com/sun/jndi/ldap : jdk/src/share/classes/com/sun/jndi/ldap
jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool : jdk/src/share/classes/com/sun/jndi/ldap/pool
@@ -1330,9 +1332,9 @@ jdk/src/jdk.jdwp.agent/unix/native/libdt_socket : jdk/src/solaris/transport/sock
jdk/src/jdk.jdwp.agent/unix/native/libjdwp : jdk/src/solaris/back
jdk/src/jdk.jdwp.agent/windows/native/libdt_socket : jdk/src/windows/transport/socket
jdk/src/jdk.jdwp.agent/windows/native/libjdwp : jdk/src/windows/back
-jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/monitor : jdk/src/share/classes/sun/jvmstat/monitor
-jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata : jdk/src/share/classes/sun/jvmstat/perfdata
-jdk/src/jdk.jvmstat/share/classes/sun/tools/jstatd : jdk/src/share/classes/sun/tools/jstatd
+jdk/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor : jdk/src/share/classes/sun/jvmstat/monitor
+jdk/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata : jdk/src/share/classes/sun/jvmstat/perfdata
+jdk/src/jdk.internal.jvmstat/share/classes/sun/tools/jstatd : jdk/src/share/classes/sun/tools/jstatd
jdk/src/jdk.localedata/share/classes/sun/text/resources/ar : jdk/src/share/classes/sun/text/resources/ar
jdk/src/jdk.localedata/share/classes/sun/text/resources/be : jdk/src/share/classes/sun/text/resources/be
jdk/src/jdk.localedata/share/classes/sun/text/resources/bg : jdk/src/share/classes/sun/text/resources/bg
@@ -1421,6 +1423,9 @@ jdk/src/jdk.localedata/share/classes/sun/util/resources/uk : jdk/src/share/class
jdk/src/jdk.localedata/share/classes/sun/util/resources/vi : jdk/src/share/classes/sun/util/resources/vi
jdk/src/jdk.localedata/share/classes/sun/util/resources/zh : jdk/src/share/classes/sun/util/resources/zh
jdk/src/jdk.management/share/classes/com/sun/management : jdk/src/share/classes/com/sun/management
+jdk/src/jdk.management.agent/share/classes/jdk/internal/agent/resources : jdk/src/share/classes/sun/management/resources
+jdk/src/jdk.management.agent/share/classes/sun/management/jmxremote : jdk/src/share/classes/sun/management/jmxremote
+jdk/src/jdk.management.agent/share/classes/sun/management/jdp : jdk/src/share/classes/sun/management/jdp
jdk/src/jdk.naming.dns/share/classes/com/sun/jndi/dns : jdk/src/share/classes/com/sun/jndi/dns
jdk/src/jdk.naming.dns/share/classes/com/sun/jndi/url/dns : jdk/src/share/classes/com/sun/jndi/url/dns
jdk/src/jdk.naming.dns/share/classes/META-INF/services : jdk/src/share/classes/sun/net/spi/nameservice/dns/META-INF/services
diff --git a/corba/.hgtags b/corba/.hgtags
index dd78cf97c29..7a24e3f5f23 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -397,3 +397,4 @@ f95cc86b6ac22ec1ade5d4f825dc7782adeea228 jdk-9+148
ff8cb43c07c069b1debdee44cb88ca22db1ec757 jdk-9+152
68a8e8658511093b322a46ed04b2a321e1da2a43 jdk-9+153
078ebe23b584466dc8346e620d7821d91751e5a9 jdk-9+154
+a545f54babfa31aa7eb611f36031609acd617cbc jdk-9+155
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index 8a3f632ef26..66afb5ed54b 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -557,3 +557,4 @@ a82cb5350cad96a0b4de496afebe3ded89f27efa jdk-9+146
31f1d26c60df7b2e516a4f84160d76ba017d4e09 jdk-9+152
217ba81b9a4ce8698200370175aa2db86a39f66c jdk-9+153
a9fdfd55835ef9dccb7f317b07249bd66653b874 jdk-9+154
+f3b3d77a1751897413aae43ac340a130b6fa2ae1 jdk-9+155
diff --git a/hotspot/make/ide/CreateVSProject.gmk b/hotspot/make/ide/CreateVSProject.gmk
index d6f5324adb8..db0aca87e28 100644
--- a/hotspot/make/ide/CreateVSProject.gmk
+++ b/hotspot/make/ide/CreateVSProject.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -121,7 +121,7 @@ ifeq ($(OPENJDK_TARGET_OS), windows)
-buildBase $(call FixPath, $(IDE_OUTPUTDIR)/vs-output) \
-buildSpace $(call FixPath, $(IDE_OUTPUTDIR)) \
-makeBinary $(call FixPath, $(MAKE)) \
- -makeOutput $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-%f/libjvm) \
+ -makeOutput $(call FixPath, $(JDK_OUTPUTDIR)/bin/server) \
-absoluteInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \
-absoluteSrcInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \
$(EXTRACTED_DEFINES_client) \
diff --git a/hotspot/make/lib/CompileJvm.gmk b/hotspot/make/lib/CompileJvm.gmk
index 870dde18d78..36d955807ad 100644
--- a/hotspot/make/lib/CompileJvm.gmk
+++ b/hotspot/make/lib/CompileJvm.gmk
@@ -63,7 +63,7 @@ JVM_CFLAGS_INCLUDES += \
# INCLUDE_SUFFIX_* is only meant for including the proper
# platform files. Don't use it to guard code. Use the value of
# HOTSPOT_TARGET_CPU_DEFINE etc. instead.
-# Remaining TARGET_ARCH_* is needed to select the cpu specific
+# Remaining TARGET_ARCH_* is needed to select the cpu specific
# sources for 64-bit ARM ports (arm versus aarch64).
JVM_CFLAGS_TARGET_DEFINES += \
-DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \
@@ -132,7 +132,7 @@ CFLAGS_VM_VERSION := \
#
# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp.
-ifeq ($(USE_PRECOMPILED_HEADER), 0)
+ifeq ($(USE_PRECOMPILED_HEADER), false)
JVM_CFLAGS += -DDONT_USE_PRECOMPILED_HEADER
endif
@@ -145,7 +145,7 @@ ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), linux-arm)
JVM_EXCLUDE_PATTERNS += arm_64
else ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), linux-aarch64)
- # For 64-bit arm builds, we use the 64 bit hotspot/src/cpu/arm
+ # For 64-bit arm builds, we use the 64 bit hotspot/src/cpu/arm
# hotspot sources if HOTSPOT_TARGET_CPU_ARCH is set to arm.
# Exclude the aarch64 and 32 bit arm files for this build.
ifeq ($(HOTSPOT_TARGET_CPU_ARCH), arm)
diff --git a/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java b/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java
index d44fb04c588..50413e52792 100644
--- a/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java
+++ b/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -114,8 +114,8 @@ public class WinGammaPlatformVC10 extends WinGammaPlatform {
tag(cfg, "CodeAnalysisRuleAssemblies");
}
for (BuildConfig cfg : allConfigs) {
- tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile import-hotspot LOG=info");
- tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot import-hotspot LOG=info");
+ tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile hotspot LOG=info");
+ tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot hotspot LOG=info");
tagData(cfg, "NMakeCleanCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot LOG=info");
tagData(cfg, "NMakeOutput", cfg.get("MakeOutput") + Util.sep + "jvm.dll");
tagData(cfg, "NMakePreprocessorDefinitions", Util.join(";", cfg.getDefines()));
diff --git a/hotspot/make/symbols/symbols-unix b/hotspot/make/symbols/symbols-unix
index 90326d263dc..11add06efac 100644
--- a/hotspot/make/symbols/symbols-unix
+++ b/hotspot/make/symbols/symbols-unix
@@ -192,4 +192,3 @@ JVM_AddModulePackage
JVM_AddReadsModule
JVM_DefineModule
JVM_SetBootLoaderUnnamedModule
-JVM_GetModuleByPackageName
diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad
index 2294bab8db8..37e63dc9aba 100644
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad
@@ -1042,8 +1042,10 @@ class HandlerImpl {
bool is_card_mark_membar(const MemBarNode *barrier);
bool is_CAS(int opcode);
- MemBarNode *leading_to_trailing(MemBarNode *leading);
- MemBarNode *card_mark_to_leading(const MemBarNode *barrier);
+ MemBarNode *leading_to_normal(MemBarNode *leading);
+ MemBarNode *normal_to_leading(const MemBarNode *barrier);
+ MemBarNode *card_mark_to_trailing(const MemBarNode *barrier);
+ MemBarNode *trailing_to_card_mark(const MemBarNode *trailing);
MemBarNode *trailing_to_leading(const MemBarNode *trailing);
// predicates controlling emit of ldr/ldar and associated dmb
@@ -1420,28 +1422,23 @@ source %{
// leading MemBarRelease and a trailing MemBarVolatile as follows
//
// MemBarRelease
- // { || } -- optional
+ // { || } -- optional
// {MemBarCPUOrder}
- // || \\
- // || StoreX[mo_release]
- // | \ Bot / ???
- // | MergeMem
- // | /
+ // || \\
+ // || StoreX[mo_release]
+ // | \ /
+ // | MergeMem
+ // | /
// MemBarVolatile
//
// where
// || and \\ represent Ctl and Mem feeds via Proj nodes
// | \ and / indicate further routing of the Ctl and Mem feeds
//
- // Note that the memory feed from the CPUOrder membar to the
- // MergeMem node is an AliasIdxBot slice while the feed from the
- // StoreX is for a slice determined by the type of value being
- // written.
- //
- // the diagram above shows the graph we see for non-object stores.
- // for a volatile Object store (StoreN/P) we may see other nodes
- // below the leading membar because of the need for a GC pre- or
- // post-write barrier.
+ // this is the graph we see for non-object stores. however, for a
+ // volatile Object store (StoreN/P) we may see other nodes below the
+ // leading membar because of the need for a GC pre- or post-write
+ // barrier.
//
// with most GC configurations we with see this simple variant which
// includes a post-write barrier card mark.
@@ -1449,7 +1446,7 @@ source %{
// MemBarRelease______________________________
// || \\ Ctl \ \\
// || StoreN/P[mo_release] CastP2X StoreB/CM
- // | \ Bot / oop . . . /
+ // | \ / . . . /
// | MergeMem
// | /
// || /
@@ -1459,142 +1456,152 @@ source %{
// the object address to an int used to compute the card offset) and
// Ctl+Mem to a StoreB node (which does the actual card mark).
//
- // n.b. a StoreCM node is only ever used when CMS (with or without
- // CondCardMark) or G1 is configured. This abstract instruction
- // differs from a normal card mark write (StoreB) because it implies
- // a requirement to order visibility of the card mark (StoreCM)
- // after that of the object put (StoreP/N) using a StoreStore memory
- // barrier. Note that this is /not/ a requirement to order the
- // instructions in the generated code (that is already guaranteed by
- // the order of memory dependencies). Rather it is a requirement to
- // ensure visibility order which only applies on architectures like
- // AArch64 which do not implement TSO. This ordering is required for
- // both non-volatile and volatile puts.
- //
- // That implies that we need to translate a StoreCM using the
- // sequence
+ // n.b. a StoreCM node will only appear in this configuration when
+ // using CMS. StoreCM differs from a normal card mark write (StoreB)
+ // because it implies a requirement to order visibility of the card
+ // mark (StoreCM) relative to the object put (StoreP/N) using a
+ // StoreStore memory barrier (arguably this ought to be represented
+ // explicitly in the ideal graph but that is not how it works). This
+ // ordering is required for both non-volatile and volatile
+ // puts. Normally that means we need to translate a StoreCM using
+ // the sequence
//
// dmb ishst
// stlrb
//
- // This dmb cannot be omitted even when the associated StoreX or
- // CompareAndSwapX is implemented using stlr. However, as described
- // below there are circumstances where a specific GC configuration
- // requires a stronger barrier in which case it can be omitted.
- //
- // With the Serial or Parallel GC using +CondCardMark the card mark
- // is performed conditionally on it currently being unmarked in
- // which case the volatile put graph looks slightly different
+ // However, in the case of a volatile put if we can recognise this
+ // configuration and plant an stlr for the object write then we can
+ // omit the dmb and just plant an strb since visibility of the stlr
+ // is ordered before visibility of subsequent stores. StoreCM nodes
+ // also arise when using G1 or using CMS with conditional card
+ // marking. In these cases (as we shall see) we don't need to insert
+ // the dmb when translating StoreCM because there is already an
+ // intervening StoreLoad barrier between it and the StoreP/N.
+ //
+ // It is also possible to perform the card mark conditionally on it
+ // currently being unmarked in which case the volatile put graph
+ // will look slightly different
//
// MemBarRelease____________________________________________
// || \\ Ctl \ Ctl \ \\ Mem \
// || StoreN/P[mo_release] CastP2X If LoadB |
- // | \ Bot / oop \ |
+ // | \ / \ |
// | MergeMem . . . StoreB
// | / /
// || /
// MemBarVolatile
//
- // It is worth noting at this stage that all the above
+ // It is worth noting at this stage that both the above
// configurations can be uniquely identified by checking that the
// memory flow includes the following subgraph:
//
// MemBarRelease
// {MemBarCPUOrder}
- // | \ . . .
- // | StoreX[mo_release] . . .
- // Bot | / oop
- // MergeMem
- // |
+ // | \ . . .
+ // | StoreX[mo_release] . . .
+ // | /
+ // MergeMem
+ // |
// MemBarVolatile
//
- // This is referred to as a *normal* volatile store subgraph. It can
- // easily be detected starting from any candidate MemBarRelease,
- // StoreX[mo_release] or MemBarVolatile node.
+ // This is referred to as a *normal* subgraph. It can easily be
+ // detected starting from any candidate MemBarRelease,
+ // StoreX[mo_release] or MemBarVolatile.
//
- // A small variation on this normal case occurs for an unsafe CAS
- // operation. The basic memory flow subgraph for a non-object CAS is
- // as follows
+ // A simple variation on this normal case occurs for an unsafe CAS
+ // operation. The basic graph for a non-object CAS is
//
// MemBarRelease
// ||
// MemBarCPUOrder
- // | \\ . . .
- // | CompareAndSwapX
- // | |
- // Bot | SCMemProj
- // \ / Bot
- // MergeMem
- // /
+ // || \\ . . .
+ // || CompareAndSwapX
+ // || |
+ // || SCMemProj
+ // | \ /
+ // | MergeMem
+ // | /
// MemBarCPUOrder
// ||
// MemBarAcquire
//
// The same basic variations on this arrangement (mutatis mutandis)
- // occur when a card mark is introduced. i.e. the CPUOrder MemBar
- // feeds the extra CastP2X, LoadB etc nodes but the above memory
- // flow subgraph is still present.
- //
- // This is referred to as a *normal* CAS subgraph. It can easily be
- // detected starting from any candidate MemBarRelease,
- // StoreX[mo_release] or MemBarAcquire node.
+ // occur when a card mark is introduced. i.e. we se the same basic
+ // shape but the StoreP/N is replaced with CompareAndSawpP/N and the
+ // tail of the graph is a pair comprising a MemBarCPUOrder +
+ // MemBarAcquire.
//
- // The code below uses two helper predicates, leading_to_trailing
- // and trailing_to_leading to identify these normal graphs, one
- // validating the layout starting from the top membar and searching
- // down and the other validating the layout starting from the lower
- // membar and searching up.
+ // So, in the case of a CAS the normal graph has the variant form
//
- // There are two special case GC configurations when the simple
- // normal graphs above may not be generated: when using G1 (which
- // always employs a conditional card mark); and when using CMS with
- // conditional card marking (+CondCardMark) configured. These GCs
- // are both concurrent rather than stop-the world GCs. So they
- // introduce extra Ctl+Mem flow into the graph between the leading
- // and trailing membar nodes, in particular enforcing stronger
- // memory serialisation beween the object put and the corresponding
- // conditional card mark. CMS employs a post-write GC barrier while
- // G1 employs both a pre- and post-write GC barrier.
+ // MemBarRelease
+ // MemBarCPUOrder
+ // | \ . . .
+ // | CompareAndSwapX . . .
+ // | |
+ // | SCMemProj
+ // | / . . .
+ // MergeMem
+ // |
+ // MemBarCPUOrder
+ // MemBarAcquire
//
- // The post-write barrier subgraph for these configurations includes
- // a MemBarVolatile node -- referred to as a card mark membar --
- // which is needed to order the card write (StoreCM) operation in
- // the barrier, the preceding StoreX (or CompareAndSwapX) and Store
- // operations performed by GC threads i.e. a card mark membar
- // constitutes a StoreLoad barrier hence must be translated to a dmb
- // ish (whether or not it sits inside a volatile store sequence).
+ // This graph can also easily be detected starting from any
+ // candidate MemBarRelease, CompareAndSwapX or MemBarAcquire.
//
- // Of course, the use of the dmb ish for the card mark membar also
- // implies theat the StoreCM which follows can omit the dmb ishst
- // instruction. The necessary visibility ordering will already be
- // guaranteed by the dmb ish. In sum, the dmb ishst instruction only
- // needs to be generated for as part of the StoreCM sequence with GC
- // configuration +CMS -CondCardMark.
- //
- // Of course all these extra barrier nodes may well be absent --
- // they are only inserted for object puts. Their potential presence
- // significantly complicates the task of identifying whether a
- // MemBarRelease, StoreX[mo_release], MemBarVolatile or
- // MemBarAcquire forms part of a volatile put or CAS when using
- // these GC configurations (see below) and also complicates the
- // decision as to how to translate a MemBarVolatile and StoreCM.
+ // the code below uses two helper predicates, leading_to_normal and
+ // normal_to_leading to identify these normal graphs, one validating
+ // the layout starting from the top membar and searching down and
+ // the other validating the layout starting from the lower membar
+ // and searching up.
//
- // So, thjis means that a card mark MemBarVolatile occurring in the
- // post-barrier graph it needs to be distinguished from a normal
- // trailing MemBarVolatile. Resolving this is straightforward: a
- // card mark MemBarVolatile always projects a Mem feed to a StoreCM
- // node and that is a unique marker
+ // There are two special case GC configurations when a normal graph
+ // may not be generated: when using G1 (which always employs a
+ // conditional card mark); and when using CMS with conditional card
+ // marking configured. These GCs are both concurrent rather than
+ // stop-the world GCs. So they introduce extra Ctl+Mem flow into the
+ // graph between the leading and trailing membar nodes, in
+ // particular enforcing stronger memory serialisation beween the
+ // object put and the corresponding conditional card mark. CMS
+ // employs a post-write GC barrier while G1 employs both a pre- and
+ // post-write GC barrier. Of course the extra nodes may be absent --
+ // they are only inserted for object puts. This significantly
+ // complicates the task of identifying whether a MemBarRelease,
+ // StoreX[mo_release] or MemBarVolatile forms part of a volatile put
+ // when using these GC configurations (see below). It adds similar
+ // complexity to the task of identifying whether a MemBarRelease,
+ // CompareAndSwapX or MemBarAcquire forms part of a CAS.
+ //
+ // In both cases the post-write subtree includes an auxiliary
+ // MemBarVolatile (StoreLoad barrier) separating the object put and
+ // the read of the corresponding card. This poses two additional
+ // problems.
+ //
+ // Firstly, a card mark MemBarVolatile needs to be distinguished
+ // from a normal trailing MemBarVolatile. Resolving this first
+ // problem is straightforward: a card mark MemBarVolatile always
+ // projects a Mem feed to a StoreCM node and that is a unique marker
//
// MemBarVolatile (card mark)
// C | \ . . .
// | StoreCM . . .
// . . .
//
- // Returning to the task of translating the object put and the
- // leading/trailing membar nodes: what do the node graphs look like
- // for these 2 special cases? and how can we determine the status of
- // a MemBarRelease, StoreX[mo_release] or MemBarVolatile in both
- // normal and non-normal cases?
+ // The second problem is how the code generator is to translate the
+ // card mark barrier? It always needs to be translated to a "dmb
+ // ish" instruction whether or not it occurs as part of a volatile
+ // put. A StoreLoad barrier is needed after the object put to ensure
+ // i) visibility to GC threads of the object put and ii) visibility
+ // to the mutator thread of any card clearing write by a GC
+ // thread. Clearly a normal store (str) will not guarantee this
+ // ordering but neither will a releasing store (stlr). The latter
+ // guarantees that the object put is visible but does not guarantee
+ // that writes by other threads have also been observed.
+ //
+ // So, returning to the task of translating the object put and the
+ // leading/trailing membar nodes: what do the non-normal node graph
+ // look like for these 2 special cases? and how can we determine the
+ // status of a MemBarRelease, StoreX[mo_release] or MemBarVolatile
+ // in both normal and non-normal cases?
//
// A CMS GC post-barrier wraps its card write (StoreCM) inside an If
// which selects conditonal execution based on the value loaded
@@ -1605,117 +1612,91 @@ source %{
// which looks like this
//
// MemBarRelease
- // MemBarCPUOrder_(leading)____________________
- // C | | M \ \\ M | C \
- // | | \ StoreN/P[mo_release] | CastP2X
- // | | Bot \ / oop \ |
- // | | MergeMem \ /
- // | | / | /
- // MemBarVolatile (card mark) | /
- // C | || M | | /
- // | LoadB | Bot oop | / Bot
- // | | | / /
- // | Cmp |\ / /
- // | / | \ / /
- // If | \ / /
- // | \ | \ / /
- // IfFalse IfTrue | \ / /
- // \ / \ | | / /
- // \ / StoreCM | / /
- // \ / \ / / /
- // Region Phi / /
- // | \ Raw | / /
- // | . . . | / /
+ // MemBarCPUOrder_(leading)__________________
+ // C | M \ \\ C \
+ // | \ StoreN/P[mo_release] CastP2X
+ // | Bot \ /
+ // | MergeMem
+ // | /
+ // MemBarVolatile (card mark)
+ // C | || M |
+ // | LoadB |
+ // | | |
+ // | Cmp |\
+ // | / | \
+ // If | \
+ // | \ | \
+ // IfFalse IfTrue | \
+ // \ / \ | \
+ // \ / StoreCM |
+ // \ / | |
+ // Region . . . |
+ // | \ /
+ // | . . . \ / Bot
// | MergeMem
- // | |
+ // | |
// MemBarVolatile (trailing)
//
- // Notice that there are two MergeMem nodes below the leading
- // membar. The first MergeMem merges the AliasIdxBot Mem slice from
- // the leading membar and the oopptr Mem slice from the Store into
- // the card mark membar. The trailing MergeMem merges the
- // AliasIdxBot Mem slice from the leading membar, the AliasIdxRaw
- // slice from the StoreCM and an oop slice from the StoreN/P node
- // into the trailing membar (n.b. the raw slice proceeds via a Phi
- // associated with the If region).
+ // The first MergeMem merges the AliasIdxBot Mem slice from the
+ // leading membar and the oopptr Mem slice from the Store into the
+ // card mark membar. The trailing MergeMem merges the AliasIdxBot
+ // Mem slice from the card mark membar and the AliasIdxRaw slice
+ // from the StoreCM into the trailing membar (n.b. the latter
+ // proceeds via a Phi associated with the If region).
//
- // So, in the case of CMS + CondCardMark the volatile object store
- // graph still includes a normal volatile store subgraph from the
- // leading membar to the trailing membar. However, it also contains
- // the same shape memory flow to the card mark membar. The two flows
- // can be distinguished by testing whether or not the downstream
- // membar is a card mark membar.
- //
- // The graph for a CAS also varies with CMS + CondCardMark, in
- // particular employing a control feed from the CompareAndSwapX node
- // through a CmpI and If to the card mark membar and StoreCM which
- // updates the associated card. This avoids executing the card mark
- // if the CAS fails. However, it can be seen from the diagram below
- // that the presence of the barrier does not alter the normal CAS
- // memory subgraph where the leading membar feeds a CompareAndSwapX,
- // an SCMemProj, a MergeMem then a final trailing MemBarCPUOrder and
- // MemBarAcquire pair.
+ // The graph for a CAS varies slightly, the obvious difference being
+ // that the StoreN/P node is replaced by a CompareAndSwapP/N node
+ // and the trailing MemBarVolatile by a MemBarCPUOrder +
+ // MemBarAcquire pair. The other important difference is that the
+ // CompareAndSwap node's SCMemProj is not merged into the card mark
+ // membar - it still feeds the trailing MergeMem. This also means
+ // that the card mark membar receives its Mem feed directly from the
+ // leading membar rather than via a MergeMem.
//
// MemBarRelease
- // MemBarCPUOrder__(leading)_______________________
- // C / M | \\ C \
- // . . . | Bot CompareAndSwapN/P CastP2X
- // | C / M |
- // | CmpI |
- // | / |
- // | . . . |
- // | IfTrue |
- // | / |
- // MemBarVolatile (card mark) |
- // C | || M | |
- // | LoadB | Bot ______/|
- // | | | / |
- // | Cmp | / SCMemProj
- // | / | / |
- // If | / /
- // | \ | / / Bot
- // IfFalse IfTrue | / /
- // | / \ / / prec /
- // . . . | / StoreCM /
- // \ | / | raw /
- // Region . . . /
- // | \ /
- // | . . . \ / Bot
- // | MergeMem
- // | /
- // MemBarCPUOrder
- // MemBarAcquire (trailing)
+ // MemBarCPUOrder__(leading)_________________________
+ // || \\ C \
+ // MemBarVolatile (card mark) CompareAndSwapN/P CastP2X
+ // C | || M | |
+ // | LoadB | ______/|
+ // | | | / |
+ // | Cmp | / SCMemProj
+ // | / | / |
+ // If | / /
+ // | \ | / /
+ // IfFalse IfTrue | / /
+ // \ / \ |/ prec /
+ // \ / StoreCM /
+ // \ / | /
+ // Region . . . /
+ // | \ /
+ // | . . . \ / Bot
+ // | MergeMem
+ // | |
+ // MemBarCPUOrder
+ // MemBarAcquire (trailing)
//
// This has a slightly different memory subgraph to the one seen
- // previously but the core of it has a similar memory flow to the
- // CAS normal subgraph:
+ // previously but the core of it is the same as for the CAS normal
+ // sungraph
//
// MemBarRelease
// MemBarCPUOrder____
- // | \ . . .
- // | CompareAndSwapX . . .
- // | C / M |
- // | CmpI |
- // | / |
- // | . . /
- // Bot | IfTrue /
- // | / /
- // MemBarVolatile /
- // | ... /
- // StoreCM ... /
- // | /
- // . . . SCMemProj
- // Raw \ / Bot
- // MergeMem
- // |
+ // || \ . . .
+ // MemBarVolatile CompareAndSwapX . . .
+ // | \ |
+ // . . . SCMemProj
+ // | / . . .
+ // MergeMem
+ // |
// MemBarCPUOrder
// MemBarAcquire
//
- // The G1 graph for a volatile object put is a lot more complicated.
- // Nodes inserted on behalf of G1 may comprise: a pre-write graph
- // which adds the old value to the SATB queue; the releasing store
- // itself; and, finally, a post-write graph which performs a card
- // mark.
+ //
+ // G1 is quite a lot more complicated. The nodes inserted on behalf
+ // of G1 may comprise: a pre-write graph which adds the old value to
+ // the SATB queue; the releasing store itself; and, finally, a
+ // post-write graph which performs a card mark.
//
// The pre-write graph may be omitted, but only when the put is
// writing to a newly allocated (young gen) object and then only if
@@ -1753,60 +1734,25 @@ source %{
// | CastP2X | StoreN/P[mo_release] |
// | | | |
// C | M | M | M |
- // \ | Raw | oop / Bot
+ // \ | | /
// . . .
// (post write subtree elided)
// . . .
// C \ M /
// MemBarVolatile (trailing)
//
- // Note that the three memory feeds into the post-write tree are an
- // AliasRawIdx slice associated with the writes in the pre-write
- // tree, an oop type slice from the StoreX specific to the type of
- // the volatile field and the AliasBotIdx slice emanating from the
- // leading membar.
- //
// n.b. the LoadB in this subgraph is not the card read -- it's a
// read of the SATB queue active flag.
//
- // The CAS graph is once again a variant of the above with a
- // CompareAndSwapX node and SCMemProj in place of the StoreX. The
- // value from the CompareAndSwapX node is fed into the post-write
- // graph aling with the AliasIdxRaw feed from the pre-barrier and
- // the AliasIdxBot feeds from the leading membar and the ScMemProj.
- //
- // MemBarRelease (leading)____________
- // C | || M \ M \ M \ M \ . . .
- // | LoadB \ LoadL LoadN \
- // | / \ \
- // If |\ \
- // | \ | \ \
- // IfFalse IfTrue | \ \
- // | | | \ \
- // | If | \ |
- // | | \ |
- // | \ |
- // | . . . \ |
- // | / | / \ |
- // Region Phi[M] \ |
- // | \ | \ |
- // | \_____ | | |
- // C | C \ | | |
- // | CastP2X | CompareAndSwapX |
- // | | res | | |
- // C | M | | SCMemProj M |
- // \ | Raw | | Bot / Bot
- // . . .
- // (post write subtree elided)
- // . . .
- // C \ M /
- // MemBarVolatile (trailing)
+ // Once again the CAS graph is a minor variant on the above with the
+ // expected substitutions of CompareAndSawpX for StoreN/P and
+ // MemBarCPUOrder + MemBarAcquire for trailing MemBarVolatile.
//
// The G1 post-write subtree is also optional, this time when the
// new value being written is either null or can be identified as a
// newly allocated (young gen) object with no intervening control
// flow. The latter cannot happen but the former may, in which case
- // the card mark membar is omitted and the memory feeds from the
+ // the card mark membar is omitted and the memory feeds form the
// leading membar and the SToreN/P are merged direct into the
// trailing membar as per the normal subgraph. So, the only special
// case which arises is when the post-write subgraph is generated.
@@ -1828,106 +1774,94 @@ source %{
//
// (pre-write subtree elided)
// . . . . . . . . . . . .
- // C | M | M | M |
- // Region Phi[M] StoreN |
- // | Raw | oop | Bot |
- // / \_______ |\ |\ |\
- // C / C \ . . . | \ | \ | \
- // If CastP2X . . . | \ | \ | \
- // / \ | \ | \ | \
- // / \ | \ | \ | \
- // IfFalse IfTrue | | | \
- // | | \ | / |
- // | If \ | \ / \ |
- // | / \ \ | / \ |
- // | / \ \ | / \ | |
- // | IfFalse IfTrue MergeMem \ | |
- // | . . . / \ | \ | |
- // | / \ | | | |
- // | IfFalse IfTrue | | | |
- // | . . . | | | | |
- // | If / | | |
- // | / \ / | | |
- // | / \ / | | |
- // | IfFalse IfTrue / | | |
- // | . . . | / | | |
- // | \ / | | |
- // | \ / | | |
- // | MemBarVolatile__(card mark ) | | |
- // | || C | \ | | |
- // | LoadB If | / | |
- // | / \ Raw | / / /
- // | . . . | / / /
- // | \ | / / /
- // | StoreCM / / /
- // | | / / /
- // | . . . / /
- // | / /
- // | . . . / /
- // | | | / / /
- // | | Phi[M] / / /
- // | | | / / /
- // | | | / / /
- // | Region . . . Phi[M] / /
- // | | | / /
- // \ | | / /
- // \ | . . . | / /
- // \ | | / /
- // Region Phi[M] / /
- // | \ / /
- // \ MergeMem
- // \ /
- // MemBarVolatile
+ // C | M | M | M |
+ // Region Phi[M] StoreN |
+ // | / \ | |
+ // / \_______ / \ | |
+ // C / C \ . . . \ | |
+ // If CastP2X . . . | | |
+ // / \ | | |
+ // / \ | | |
+ // IfFalse IfTrue | | |
+ // | | | | /|
+ // | If | | / |
+ // | / \ | | / |
+ // | / \ \ | / |
+ // | IfFalse IfTrue MergeMem |
+ // | . . . / \ / |
+ // | / \ / |
+ // | IfFalse IfTrue / |
+ // | . . . | / |
+ // | If / |
+ // | / \ / |
+ // | / \ / |
+ // | IfFalse IfTrue / |
+ // | . . . | / |
+ // | \ / |
+ // | \ / |
+ // | MemBarVolatile__(card mark) |
+ // | || C | M \ M \ |
+ // | LoadB If | | |
+ // | / \ | | |
+ // | . . . | | |
+ // | \ | | /
+ // | StoreCM | /
+ // | . . . | /
+ // | _________/ /
+ // | / _____________/
+ // | . . . . . . | / /
+ // | | | / _________/
+ // | | Phi[M] / /
+ // | | | / /
+ // | | | / /
+ // | Region . . . Phi[M] _____/
+ // | / | /
+ // | | /
+ // | . . . . . . | /
+ // | / | /
+ // Region | | Phi[M]
+ // | | | / Bot
+ // \ MergeMem
+ // \ /
+ // MemBarVolatile
//
- // As with CMS + CondCardMark the first MergeMem merges the
- // AliasIdxBot Mem slice from the leading membar and the oopptr Mem
- // slice from the Store into the card mark membar. However, in this
- // case it may also merge an AliasRawIdx mem slice from the pre
- // barrier write.
+ // As with CMS the initial MergeMem merges the AliasIdxBot Mem slice
+ // from the leading membar and the oopptr Mem slice from the Store
+ // into the card mark membar i.e. the memory flow to the card mark
+ // membar still looks like a normal graph.
//
- // The trailing MergeMem merges an AliasIdxBot Mem slice from the
- // leading membar with an oop slice from the StoreN and an
- // AliasRawIdx slice from the post barrier writes. In this case the
- // AliasIdxRaw Mem slice is merged through a series of Phi nodes
- // which combine feeds from the If regions in the post barrier
- // subgraph.
+ // The trailing MergeMem merges an AliasIdxBot Mem slice with other
+ // Mem slices (from the StoreCM and other card mark queue stores).
+ // However in this case the AliasIdxBot Mem slice does not come
+ // direct from the card mark membar. It is merged through a series
+ // of Phi nodes. These are needed to merge the AliasIdxBot Mem flow
+ // from the leading membar with the Mem feed from the card mark
+ // membar. Each Phi corresponds to one of the Ifs which may skip
+ // around the card mark membar. So when the If implementing the NULL
+ // value check has been elided the total number of Phis is 2
+ // otherwise it is 3.
//
- // So, for G1 the same characteristic subgraph arises as for CMS +
- // CondCardMark. There is a normal subgraph feeding the card mark
- // membar and a normal subgraph feeding the trailing membar.
+ // The CAS graph when using G1GC also includes a pre-write subgraph
+ // and an optional post-write subgraph. Teh sam evarioations are
+ // introduced as for CMS with conditional card marking i.e. the
+ // StoreP/N is swapped for a CompareAndSwapP/N, the tariling
+ // MemBarVolatile for a MemBarCPUOrder + MemBarAcquire pair and the
+ // Mem feed from the CompareAndSwapP/N includes a precedence
+ // dependency feed to the StoreCM and a feed via an SCMemProj to the
+ // trailing membar. So, as before the configuration includes the
+ // normal CAS graph as a subgraph of the memory flow.
//
- // The CAS graph when using G1GC also includes an optional
- // post-write subgraph. It is very similar to the above graph except
- // for a few details.
- //
- // - The control flow is gated by an additonal If which tests the
- // result from the CompareAndSwapX node
- //
- // - The MergeMem which feeds the card mark membar only merges the
- // AliasIdxBot slice from the leading membar and the AliasIdxRaw
- // slice from the pre-barrier. It does not merge the SCMemProj
- // AliasIdxBot slice. So, this subgraph does not look like the
- // normal CAS subgraph.
- //
- // - The MergeMem which feeds the trailing membar merges the
- // AliasIdxBot slice from the leading membar, the AliasIdxRaw slice
- // from the post-barrier and the SCMemProj AliasIdxBot slice i.e. it
- // has two AliasIdxBot input slices. However, this subgraph does
- // still look like the normal CAS subgraph.
- //
- // So, the upshot is:
- //
- // In all cases a volatile put graph will include a *normal*
- // volatile store subgraph betwen the leading membar and the
- // trailing membar. It may also include a normal volatile store
- // subgraph betwen the leading membar and the card mark membar.
- //
- // In all cases a CAS graph will contain a unique normal CAS graph
- // feeding the trailing membar.
- //
- // In all cases where there is a card mark membar (either as part of
- // a volatile object put or CAS) it will be fed by a MergeMem whose
- // AliasIdxBot slice feed will be a leading membar.
+ // So, the upshot is that in all cases the volatile put graph will
+ // include a *normal* memory subgraph betwen the leading membar and
+ // its child membar, either a volatile put graph (including a
+ // releasing StoreX) or a CAS graph (including a CompareAndSwapX).
+ // When that child is not a card mark membar then it marks the end
+ // of the volatile put or CAS subgraph. If the child is a card mark
+ // membar then the normal subgraph will form part of a volatile put
+ // subgraph if and only if the child feeds an AliasIdxBot Mem feed
+ // to a trailing barrier via a MergeMem. That feed is either direct
+ // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier
+ // memory flow (for G1).
//
// The predicates controlling generation of instructions for store
// and barrier nodes employ a few simple helper functions (described
@@ -1971,24 +1905,24 @@ source %{
}
- // leading_to_trailing
+ // leading_to_normal
//
//graph traversal helper which detects the normal case Mem feed from
// a release membar (or, optionally, its cpuorder child) to a
// dependent volatile membar i.e. it ensures that one or other of
// the following Mem flow subgraph is present.
//
- // MemBarRelease {leading}
- // {MemBarCPUOrder} {optional}
- // Bot | \ . . .
- // | StoreN/P[mo_release] . . .
- // | /
- // MergeMem
- // |
- // MemBarVolatile {not card mark}
+ // MemBarRelease
+ // MemBarCPUOrder {leading}
+ // | \ . . .
+ // | StoreN/P[mo_release] . . .
+ // | /
+ // MergeMem
+ // |
+ // MemBarVolatile {trailing or card mark}
//
- // MemBarRelease {leading}
- // {MemBarCPUOrder} {optional}
+ // MemBarRelease
+ // MemBarCPUOrder {leading}
// | \ . . .
// | CompareAndSwapX . . .
// |
@@ -1999,23 +1933,6 @@ source %{
// MemBarCPUOrder
// MemBarAcquire {trailing}
//
- // the predicate needs to be capable of distinguishing the following
- // volatile put graph which may arises when a GC post barrier
- // inserts a card mark membar
- //
- // MemBarRelease {leading}
- // {MemBarCPUOrder}__
- // Bot | \ \
- // | StoreN/P \
- // | / \ |
- // MergeMem \ |
- // | \ |
- // MemBarVolatile \ |
- // {card mark} \ |
- // MergeMem
- // |
- // {not card mark} MemBarVolatile
- //
// if the correct configuration is present returns the trailing
// membar otherwise NULL.
//
@@ -2026,7 +1943,7 @@ source %{
// the returned value may be a card mark or trailing membar
//
- MemBarNode *leading_to_trailing(MemBarNode *leading)
+ MemBarNode *leading_to_normal(MemBarNode *leading)
{
assert((leading->Opcode() == Op_MemBarRelease ||
leading->Opcode() == Op_MemBarCPUOrder),
@@ -2043,21 +1960,15 @@ source %{
StoreNode * st = NULL;
LoadStoreNode *cas = NULL;
MergeMemNode *mm = NULL;
- MergeMemNode *mm2 = NULL;
for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
x = mem->fast_out(i);
if (x->is_MergeMem()) {
if (mm != NULL) {
- if (mm2 != NULL) {
- // should not see more than 2 merge mems
- return NULL;
- } else {
- mm2 = x->as_MergeMem();
- }
- } else {
- mm = x->as_MergeMem();
+ return NULL;
}
+ // two merge mems is one too many
+ mm = x->as_MergeMem();
} else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) {
// two releasing stores/CAS nodes is one too many
if (st != NULL || cas != NULL) {
@@ -2077,13 +1988,13 @@ source %{
return NULL;
}
- // must have at least one merge if we also have st
+ // must have a merge if we also have st
if (st && !mm) {
return NULL;
}
+ Node *y = NULL;
if (cas) {
- Node *y = NULL;
// look for an SCMemProj
for (DUIterator_Fast imax, i = cas->fast_outs(imax); i < imax; i++) {
x = cas->fast_out(i);
@@ -2103,29 +2014,10 @@ source %{
break;
}
}
- if (mm == NULL) {
+ if (mm == NULL)
return NULL;
- }
- MemBarNode *mbar = NULL;
- // ensure the merge feeds a trailing membar cpuorder + acquire pair
- for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
- x = mm->fast_out(i);
- if (x->is_MemBar()) {
- int opcode = x->Opcode();
- if (opcode == Op_MemBarCPUOrder) {
- MemBarNode *z = x->as_MemBar();
- z = child_membar(z);
- if (z != NULL && z->Opcode() == Op_MemBarAcquire) {
- mbar = z;
- }
- }
- break;
- }
- }
- return mbar;
} else {
- Node *y = NULL;
- // ensure the store feeds the first mergemem;
+ // ensure the store feeds the existing mergemem;
for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) {
if (st->fast_out(i) == mm) {
y = st;
@@ -2135,89 +2027,55 @@ source %{
if (y == NULL) {
return NULL;
}
- if (mm2 != NULL) {
- // ensure the store feeds the second mergemem;
- y = NULL;
- for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) {
- if (st->fast_out(i) == mm2) {
- y = st;
- }
- }
- if (y == NULL) {
- return NULL;
- }
- }
+ }
- MemBarNode *mbar = NULL;
- // ensure the first mergemem feeds a volatile membar
- for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
- x = mm->fast_out(i);
- if (x->is_MemBar()) {
- int opcode = x->Opcode();
- if (opcode == Op_MemBarVolatile) {
- mbar = x->as_MemBar();
+ MemBarNode *mbar = NULL;
+ // ensure the merge feeds to the expected type of membar
+ for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
+ x = mm->fast_out(i);
+ if (x->is_MemBar()) {
+ int opcode = x->Opcode();
+ if (opcode == Op_MemBarVolatile && st) {
+ mbar = x->as_MemBar();
+ } else if (cas && opcode == Op_MemBarCPUOrder) {
+ MemBarNode *y = x->as_MemBar();
+ y = child_membar(y);
+ if (y != NULL && y->Opcode() == Op_MemBarAcquire) {
+ mbar = y;
}
- break;
- }
- }
- if (mm2 == NULL) {
- // this is our only option for a trailing membar
- return mbar;
- }
- // ensure the second mergemem feeds a volatile membar
- MemBarNode *mbar2 = NULL;
- for (DUIterator_Fast imax, i = mm2->fast_outs(imax); i < imax; i++) {
- x = mm2->fast_out(i);
- if (x->is_MemBar()) {
- int opcode = x->Opcode();
- if (opcode == Op_MemBarVolatile) {
- mbar2 = x->as_MemBar();
- }
- break;
- }
- }
- // if we have two merge mems we must have two volatile membars
- if (mbar == NULL || mbar2 == NULL) {
- return NULL;
- }
- // return the trailing membar
- if (is_card_mark_membar(mbar2)) {
- return mbar;
- } else {
- if (is_card_mark_membar(mbar)) {
- return mbar2;
- } else {
- return NULL;
}
+ break;
}
}
+
+ return mbar;
}
- // trailing_to_leading
+ // normal_to_leading
//
// graph traversal helper which detects the normal case Mem feed
- // from a trailing membar to a preceding release membar (optionally
- // its cpuorder child) i.e. it ensures that one or other of the
- // following Mem flow subgraphs is present.
+ // from either a card mark or a trailing membar to a preceding
+ // release membar (optionally its cpuorder child) i.e. it ensures
+ // that one or other of the following Mem flow subgraphs is present.
//
- // MemBarRelease {leading}
- // MemBarCPUOrder {optional}
- // | Bot | \ . . .
- // | | StoreN/P[mo_release] . . .
- // | | /
- // | MergeMem
- // | |
- // MemBarVolatile {not card mark}
+ // MemBarRelease
+ // MemBarCPUOrder {leading}
+ // | \ . . .
+ // | StoreN/P[mo_release] . . .
+ // | /
+ // MergeMem
+ // |
+ // MemBarVolatile {card mark or trailing}
//
- // MemBarRelease {leading}
- // MemBarCPUOrder {optional}
+ // MemBarRelease
+ // MemBarCPUOrder {leading}
// | \ . . .
// | CompareAndSwapX . . .
// |
// . . . SCMemProj
// \ |
// | MergeMem
- // | |
+ // | /
// MemBarCPUOrder
// MemBarAcquire {trailing}
//
@@ -2227,20 +2085,15 @@ source %{
// if the configuration is present returns the cpuorder member for
// preference or when absent the release membar otherwise NULL.
//
- // n.b. the input membar is expected to be a MemBarVolatile or
- // MemBarAcquire. if it is a MemBarVolatile it must *not* be a card
- // mark membar.
+ // n.b. the input membar is expected to be a MemBarVolatile but
+ // need not be a card mark membar.
- MemBarNode *trailing_to_leading(const MemBarNode *barrier)
+ MemBarNode *normal_to_leading(const MemBarNode *barrier)
{
// input must be a volatile membar
assert((barrier->Opcode() == Op_MemBarVolatile ||
barrier->Opcode() == Op_MemBarAcquire),
"expecting a volatile or an acquire membar");
-
- assert((barrier->Opcode() != Op_MemBarVolatile) ||
- !is_card_mark_membar(barrier),
- "not expecting a card mark membar");
Node *x;
bool is_cas = barrier->Opcode() == Op_MemBarAcquire;
@@ -2353,35 +2206,169 @@ source %{
return NULL;
}
- // card_mark_to_leading
+ // card_mark_to_trailing
//
- // graph traversal helper which traverses from a card mark volatile
- // membar to a leading membar i.e. it ensures that the following Mem
- // flow subgraph is present.
+ // graph traversal helper which detects extra, non-normal Mem feed
+ // from a card mark volatile membar to a trailing membar i.e. it
+ // ensures that one of the following three GC post-write Mem flow
+ // subgraphs is present.
//
- // MemBarRelease {leading}
- // {MemBarCPUOrder} {optional}
- // | . . .
+ // 1)
+ // . . .
+ // |
+ // MemBarVolatile (card mark)
+ // | |
+ // | StoreCM
+ // | |
+ // | . . .
+ // Bot | /
+ // MergeMem
+ // |
+ // |
+ // MemBarVolatile {trailing}
+ //
+ // 2)
+ // MemBarRelease/CPUOrder (leading)
+ // |
+ // |
+ // |\ . . .
+ // | \ |
+ // | \ MemBarVolatile (card mark)
+ // | \ | |
+ // \ \ | StoreCM . . .
+ // \ \ |
+ // \ Phi
+ // \ /
+ // Phi . . .
// Bot | /
- // MergeMem
+ // MergeMem
// |
- // MemBarVolatile (card mark)
- // | \
- // . . . StoreCM
+ // MemBarVolatile {trailing}
//
- // if the configuration is present returns the cpuorder member for
- // preference or when absent the release membar otherwise NULL.
//
- // n.b. the input membar is expected to be a MemBarVolatile amd must
- // be a card mark membar.
+ // 3)
+ // MemBarRelease/CPUOrder (leading)
+ // |
+ // |\
+ // | \
+ // | \ . . .
+ // | \ |
+ // |\ \ MemBarVolatile (card mark)
+ // | \ \ | |
+ // | \ \ | StoreCM . . .
+ // | \ \ |
+ // \ \ Phi
+ // \ \ /
+ // \ Phi
+ // \ /
+ // Phi . . .
+ // Bot | /
+ // MergeMem
+ // |
+ // |
+ // MemBarVolatile {trailing}
+ //
+ // configuration 1 is only valid if UseConcMarkSweepGC &&
+ // UseCondCardMark
+ //
+ // configurations 2 and 3 are only valid if UseG1GC.
+ //
+ // if a valid configuration is present returns the trailing membar
+ // otherwise NULL.
+ //
+ // n.b. the supplied membar is expected to be a card mark
+ // MemBarVolatile i.e. the caller must ensure the input node has the
+ // correct operand and feeds Mem to a StoreCM node
- MemBarNode *card_mark_to_leading(const MemBarNode *barrier)
+ MemBarNode *card_mark_to_trailing(const MemBarNode *barrier)
{
// input must be a card mark volatile membar
assert(is_card_mark_membar(barrier), "expecting a card mark membar");
+ Node *feed = barrier->proj_out(TypeFunc::Memory);
+ Node *x;
+ MergeMemNode *mm = NULL;
+
+ const int MAX_PHIS = 3; // max phis we will search through
+ int phicount = 0; // current search count
+
+ bool retry_feed = true;
+ while (retry_feed) {
+ // see if we have a direct MergeMem feed
+ for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) {
+ x = feed->fast_out(i);
+ // the correct Phi will be merging a Bot memory slice
+ if (x->is_MergeMem()) {
+ mm = x->as_MergeMem();
+ break;
+ }
+ }
+ if (mm) {
+ retry_feed = false;
+ } else if (UseG1GC & phicount++ < MAX_PHIS) {
+ // the barrier may feed indirectly via one or two Phi nodes
+ PhiNode *phi = NULL;
+ for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) {
+ x = feed->fast_out(i);
+ // the correct Phi will be merging a Bot memory slice
+ if (x->is_Phi() && x->adr_type() == TypePtr::BOTTOM) {
+ phi = x->as_Phi();
+ break;
+ }
+ }
+ if (!phi) {
+ return NULL;
+ }
+ // look for another merge below this phi
+ feed = phi;
+ } else {
+ // couldn't find a merge
+ return NULL;
+ }
+ }
+
+ // sanity check this feed turns up as the expected slice
+ assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge");
+
+ MemBarNode *trailing = NULL;
+ // be sure we have a trailing membar the merge
+ for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
+ x = mm->fast_out(i);
+ if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) {
+ trailing = x->as_MemBar();
+ break;
+ }
+ }
+
+ return trailing;
+ }
+
+ // trailing_to_card_mark
+ //
+ // graph traversal helper which detects extra, non-normal Mem feed
+ // from a trailing volatile membar to a preceding card mark volatile
+ // membar i.e. it identifies whether one of the three possible extra
+ // GC post-write Mem flow subgraphs is present
+ //
+ // this predicate checks for the same flow as the previous predicate
+ // but starting from the bottom rather than the top.
+ //
+ // if the configuration is present returns the card mark membar
+ // otherwise NULL
+ //
+ // n.b. the supplied membar is expected to be a trailing
+ // MemBarVolatile i.e. the caller must ensure the input node has the
+ // correct opcode
+
+ MemBarNode *trailing_to_card_mark(const MemBarNode *trailing)
+ {
+ assert(trailing->Opcode() == Op_MemBarVolatile,
+ "expecting a volatile membar");
+ assert(!is_card_mark_membar(trailing),
+ "not expecting a card mark membar");
+
// the Mem feed to the membar should be a merge
- Node *x = barrier->in(TypeFunc::Memory);
+ Node *x = trailing->in(TypeFunc::Memory);
if (!x->is_MergeMem()) {
return NULL;
}
@@ -2389,20 +2376,118 @@ source %{
MergeMemNode *mm = x->as_MergeMem();
x = mm->in(Compile::AliasIdxBot);
+ // with G1 we may possibly see a Phi or two before we see a Memory
+ // Proj from the card mark membar
+ const int MAX_PHIS = 3; // max phis we will search through
+ int phicount = 0; // current search count
+
+ bool retry_feed = !x->is_Proj();
+
+ while (retry_feed) {
+ if (UseG1GC && x->is_Phi() && phicount++ < MAX_PHIS) {
+ PhiNode *phi = x->as_Phi();
+ ProjNode *proj = NULL;
+ PhiNode *nextphi = NULL;
+ bool found_leading = false;
+ for (uint i = 1; i < phi->req(); i++) {
+ x = phi->in(i);
+ if (x->is_Phi()) {
+ nextphi = x->as_Phi();
+ } else if (x->is_Proj()) {
+ int opcode = x->in(0)->Opcode();
+ if (opcode == Op_MemBarVolatile) {
+ proj = x->as_Proj();
+ } else if (opcode == Op_MemBarRelease ||
+ opcode == Op_MemBarCPUOrder) {
+ // probably a leading membar
+ found_leading = true;
+ }
+ }
+ }
+ // if we found a correct looking proj then retry from there
+ // otherwise we must see a leading and a phi or this the
+ // wrong config
+ if (proj != NULL) {
+ x = proj;
+ retry_feed = false;
+ } else if (found_leading && nextphi != NULL) {
+ // retry from this phi to check phi2
+ x = nextphi;
+ } else {
+ // not what we were looking for
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ }
+ // the proj has to come from the card mark membar
+ x = x->in(0);
if (!x->is_MemBar()) {
return NULL;
}
- MemBarNode *leading = x->as_MemBar();
+ MemBarNode *card_mark_membar = x->as_MemBar();
- if (leading_membar(leading)) {
+ if (!is_card_mark_membar(card_mark_membar)) {
+ return NULL;
+ }
+
+ return card_mark_membar;
+ }
+
+ // trailing_to_leading
+ //
+ // graph traversal helper which checks the Mem flow up the graph
+ // from a (non-card mark) trailing membar attempting to locate and
+ // return an associated leading membar. it first looks for a
+ // subgraph in the normal configuration (relying on helper
+ // normal_to_leading). failing that it then looks for one of the
+ // possible post-write card mark subgraphs linking the trailing node
+ // to a the card mark membar (relying on helper
+ // trailing_to_card_mark), and then checks that the card mark membar
+ // is fed by a leading membar (once again relying on auxiliary
+ // predicate normal_to_leading).
+ //
+ // if the configuration is valid returns the cpuorder member for
+ // preference or when absent the release membar otherwise NULL.
+ //
+ // n.b. the input membar is expected to be either a volatile or
+ // acquire membar but in the former case must *not* be a card mark
+ // membar.
+
+ MemBarNode *trailing_to_leading(const MemBarNode *trailing)
+ {
+ assert((trailing->Opcode() == Op_MemBarAcquire ||
+ trailing->Opcode() == Op_MemBarVolatile),
+ "expecting an acquire or volatile membar");
+ assert((trailing->Opcode() != Op_MemBarVolatile ||
+ !is_card_mark_membar(trailing)),
+ "not expecting a card mark membar");
+
+ MemBarNode *leading = normal_to_leading(trailing);
+
+ if (leading) {
return leading;
}
- return NULL;
+ // nothing more to do if this is an acquire
+ if (trailing->Opcode() == Op_MemBarAcquire) {
+ return NULL;
+ }
+
+ MemBarNode *card_mark_membar = trailing_to_card_mark(trailing);
+
+ if (!card_mark_membar) {
+ return NULL;
+ }
+
+ return normal_to_leading(card_mark_membar);
}
+ // predicates controlling emit of ldr/ldar and associated dmb
+
bool unnecessary_acquire(const Node *barrier)
{
assert(barrier->is_MemBar(), "expecting a membar");
@@ -2617,8 +2702,19 @@ bool unnecessary_release(const Node *n)
}
// must start with a normal feed
- MemBarNode *trailing = leading_to_trailing(barrier);
+ MemBarNode *child_barrier = leading_to_normal(barrier);
+ if (!child_barrier) {
+ return false;
+ }
+
+ if (!is_card_mark_membar(child_barrier)) {
+ // this is the trailing membar and we are done
+ return true;
+ }
+
+ // must be sure this card mark feeds a trailing membar
+ MemBarNode *trailing = card_mark_to_trailing(child_barrier);
return (trailing != NULL);
}
@@ -2640,7 +2736,7 @@ bool unnecessary_volatile(const Node *n)
}
// ok, if it's not a card mark then we still need to check if it is
- // a trailing membar of a volatile put graph.
+ // a trailing membar of a volatile put hgraph.
return (trailing_to_leading(mbvol) != NULL);
}
@@ -2690,9 +2786,20 @@ bool needs_releasing_store(const Node *n)
}
// does this lead a normal subgraph?
- MemBarNode *trailing = leading_to_trailing(barrier);
+ MemBarNode *mbvol = leading_to_normal(barrier);
- return (trailing != NULL);
+ if (!mbvol) {
+ return false;
+ }
+
+ // all done unless this is a card mark
+ if (!is_card_mark_membar(mbvol)) {
+ return true;
+ }
+
+ // we found a card mark -- just make sure we have a trailing barrier
+
+ return (card_mark_to_trailing(mbvol) != NULL);
}
// predicate controlling translation of CAS
@@ -2734,7 +2841,7 @@ bool needs_acquiring_load_exclusive(const Node *n)
"CAS not fed by cpuorder+release membar pair!");
// does this lead a normal subgraph?
- MemBarNode *mbar = leading_to_trailing(barrier);
+ MemBarNode *mbar = leading_to_normal(barrier);
assert(mbar != NULL, "CAS not embedded in normal graph!");
@@ -2755,27 +2862,48 @@ bool unnecessary_storestore(const Node *storecm)
// we only ever need to generate a dmb ishst between an object put
// and the associated card mark when we are using CMS without
- // conditional card marking. Any other occurence will happen when
- // performing a card mark using CMS with conditional card marking or
- // G1. In those cases the preceding MamBarVolatile will be
- // translated to a dmb ish which guarantes visibility of the
- // preceding StoreN/P before this StoreCM
+ // conditional card marking
if (!UseConcMarkSweepGC || UseCondCardMark) {
return true;
}
- // if we are implementing volatile puts using barriers then we must
- // insert the dmb ishst
+ // if we are implementing volatile puts using barriers then the
+ // object put as an str so we must insert the dmb ishst
if (UseBarriersForVolatile) {
return false;
}
- // we must be using CMS with conditional card marking so we ahve to
- // generate the StoreStore
+ // we can omit the dmb ishst if this StoreCM is part of a volatile
+ // put because in thta case the put will be implemented by stlr
+ //
+ // we need to check for a normal subgraph feeding this StoreCM.
+ // that means the StoreCM must be fed Memory from a leading membar,
+ // either a MemBarRelease or its dependent MemBarCPUOrder, and the
+ // leading membar must be part of a normal subgraph
- return false;
+ Node *x = storecm->in(StoreNode::Memory);
+
+ if (!x->is_Proj()) {
+ return false;
+ }
+
+ x = x->in(0);
+
+ if (!x->is_MemBar()) {
+ return false;
+ }
+
+ MemBarNode *leading = x->as_MemBar();
+
+ // reject invalid candidates
+ if (!leading_membar(leading)) {
+ return false;
+ }
+
+ // we can omit the StoreStore if it is the head of a normal subgraph
+ return (leading_to_normal(leading) != NULL);
}
@@ -3008,6 +3136,10 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
__ notify(Assembler::method_reentry);
}
+ if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
+ __ reserved_stack_check();
+ }
+
if (do_polling() && C->is_method_compilation()) {
__ read_polling_page(rscratch1, os::get_polling_page(), relocInfo::poll_return_type);
}
@@ -9862,7 +9994,7 @@ instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
// END This section of the file is automatically generated. Do not edit --------------
// ---------------------------------------------------------------------
-instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{
+instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) %{
match(Set prev (GetAndSetI mem newv));
format %{ "atomic_xchgw $prev, $newv, [$mem]" %}
ins_encode %{
@@ -9871,7 +10003,7 @@ instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{
ins_pipe(pipe_serial);
%}
-instruct get_and_setL(indirect mem, iRegLNoSp newv, iRegL prev) %{
+instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{
match(Set prev (GetAndSetL mem newv));
format %{ "atomic_xchg $prev, $newv, [$mem]" %}
ins_encode %{
@@ -9880,7 +10012,7 @@ instruct get_and_setL(indirect mem, iRegLNoSp newv, iRegL prev) %{
ins_pipe(pipe_serial);
%}
-instruct get_and_setN(indirect mem, iRegNNoSp newv, iRegI prev) %{
+instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{
match(Set prev (GetAndSetN mem newv));
format %{ "atomic_xchgw $prev, $newv, [$mem]" %}
ins_encode %{
@@ -9889,7 +10021,7 @@ instruct get_and_setN(indirect mem, iRegNNoSp newv, iRegI prev) %{
ins_pipe(pipe_serial);
%}
-instruct get_and_setP(indirect mem, iRegPNoSp newv, iRegP prev) %{
+instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) %{
match(Set prev (GetAndSetP mem newv));
format %{ "atomic_xchg $prev, $newv, [$mem]" %}
ins_encode %{
diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
index 70c8f909337..b139a44f9a1 100644
--- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
@@ -532,8 +532,14 @@ void LIR_Assembler::poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo*
void LIR_Assembler::return_op(LIR_Opr result) {
assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == r0, "word returns are in r0,");
+
// Pop the stack before the safepoint code
__ remove_frame(initial_frame_size_in_bytes());
+
+ if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
+ __ reserved_stack_check();
+ }
+
address polling_page(os::get_polling_page());
__ read_polling_page(rscratch1, polling_page, relocInfo::poll_return_type);
__ ret(lr);
diff --git a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp
index 58ba9c0b613..8c83dc4125c 100644
--- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -1179,6 +1179,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Label done;
Label runtime;
+ // Is marking still active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ ldrw(tmp, in_progress);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ ldrb(tmp, in_progress);
+ }
+ __ cbzw(tmp, done);
+
// Can we store original value in the thread's buffer?
__ ldr(tmp, queue_index);
__ cbz(tmp, runtime);
diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp
index b74bce2d415..fe48df281b1 100644
--- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp
@@ -375,7 +375,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
fr._unextended_sp = unextended_sp;
address original_pc = nm->get_original_pc(&fr);
- assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
+ assert(nm->insts_contains_inclusive(original_pc),
+ "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
}
#endif
@@ -629,6 +630,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
DESCRIBE_FP_OFFSET(interpreter_frame_last_sp);
DESCRIBE_FP_OFFSET(interpreter_frame_method);
DESCRIBE_FP_OFFSET(interpreter_frame_mdp);
+ DESCRIBE_FP_OFFSET(interpreter_frame_mirror);
DESCRIBE_FP_OFFSET(interpreter_frame_cache);
DESCRIBE_FP_OFFSET(interpreter_frame_locals);
DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp
index 5bcee325945..64a35bd3c30 100644
--- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp
@@ -46,6 +46,9 @@
// [pointer to locals ] = locals() locals_offset
// [constant pool cache ] = cache() cache_offset
+// [klass of method ] = mirror() mirror_offset
+// [padding ]
+
// [methodData ] = mdp() mdx_offset
// [methodOop ] = method() method_offset
diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp
index 7c410aaa74b..4f6d2bef7f5 100644
--- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp
+++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp
@@ -82,7 +82,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
- assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod");
+ assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
+ "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
diff --git a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp
index 4c9d377ff09..0d78e2da1fe 100644
--- a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp
@@ -53,4 +53,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
// evidence that it's worth doing.
#define DEOPTIMIZE_WHEN_PATCHING
+#define SUPPORT_RESERVED_STACK_AREA
+
#endif // CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP
diff --git a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp
index 926e06004dc..06ec817cd9b 100644
--- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp
@@ -50,7 +50,7 @@ define_pd_global(intx, InlineFrequencyCount, 100);
// stack if compiled for unix and LP64. To pass stack overflow tests we need
// 20 shadow pages.
#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+5))
-#define DEFAULT_STACK_RESERVED_PAGES (0)
+#define DEFAULT_STACK_RESERVED_PAGES (1)
#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp
index ed95d410e36..81636fb8ea1 100644
--- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp
@@ -619,6 +619,22 @@ void InterpreterMacroAssembler::remove_activation(
// get sender esp
ldr(esp,
Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize));
+ if (StackReservedPages > 0) {
+ // testing if reserved zone needs to be re-enabled
+ Label no_reserved_zone_enabling;
+
+ ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset()));
+ cmp(esp, rscratch1);
+ br(Assembler::LS, no_reserved_zone_enabling);
+
+ call_VM_leaf(
+ CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread);
+ call_VM(noreg, CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::throw_delayed_StackOverflowError));
+ should_not_reach_here();
+
+ bind(no_reserved_zone_enabling);
+ }
// remove frame anchor
leave();
// If we're returning to interpreted code we will shortly be
diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
index dc90886ab68..1c955d5afe3 100644
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
@@ -402,6 +402,30 @@ void MacroAssembler::far_jump(Address entry, CodeBuffer *cbuf, Register tmp) {
}
}
+void MacroAssembler::reserved_stack_check() {
+ // testing if reserved zone needs to be enabled
+ Label no_reserved_zone_enabling;
+
+ ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset()));
+ cmp(sp, rscratch1);
+ br(Assembler::LO, no_reserved_zone_enabling);
+
+ enter(); // LR and FP are live.
+ lea(rscratch1, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone));
+ mov(c_rarg0, rthread);
+ blr(rscratch1);
+ leave();
+
+ // We have already removed our own frame.
+ // throw_delayed_StackOverflowError will think that it's been
+ // called by our caller.
+ lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry()));
+ br(rscratch1);
+ should_not_reach_here();
+
+ bind(no_reserved_zone_enabling);
+}
+
int MacroAssembler::biased_locking_enter(Register lock_reg,
Register obj_reg,
Register swap_reg,
diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
index 3418189f1b4..2f17699a262 100644
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
@@ -957,6 +957,9 @@ public:
// stack overflow + shadow pages. Also, clobbers tmp
void bang_stack_size(Register size, Register tmp);
+ // Check for reserved stack access in method being exited (for JIT)
+ void reserved_stack_check();
+
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,
Register tmp,
int offset);
diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
index 681ecf34277..3143fe97d88 100644
--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
+++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
@@ -4676,8 +4676,11 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_throw_StackOverflowError_entry =
generate_throw_exception("StackOverflowError throw_exception",
CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_StackOverflowError));
+ SharedRuntime::throw_StackOverflowError));
+ StubRoutines::_throw_delayed_StackOverflowError_entry =
+ generate_throw_exception("delayed StackOverflowError throw_exception",
+ CAST_FROM_FN_PTR(address,
+ SharedRuntime::throw_delayed_StackOverflowError));
if (UseCRC32Intrinsics) {
// set table address before stub generation which use it
StubRoutines::_crc_table_adr = (address)StubRoutines::aarch64::_crc_table;
diff --git a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp
index 937dfe91242..9f17c8fc810 100644
--- a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp
+++ b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -551,6 +551,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
const Register r_index_1 = R1;
const Register r_buffer_2 = R2;
+ Address queue_active(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
+ SATBMarkQueue::byte_offset_of_active()));
Address queue_index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
SATBMarkQueue::byte_offset_of_index()));
Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
@@ -559,6 +561,11 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Label done;
Label runtime;
+ // Is marking still active?
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ ldrb(R1, queue_active);
+ __ cbz(R1, done);
+
__ ldr(r_index_1, queue_index);
__ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize));
__ ldr(r_buffer_2, buffer);
diff --git a/hotspot/src/cpu/arm/vm/frame_arm.cpp b/hotspot/src/cpu/arm/vm/frame_arm.cpp
index 55f468fa74c..defe4a45a4a 100644
--- a/hotspot/src/cpu/arm/vm/frame_arm.cpp
+++ b/hotspot/src/cpu/arm/vm/frame_arm.cpp
@@ -364,7 +364,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
fr._unextended_sp = unextended_sp;
address original_pc = nm->get_original_pc(&fr);
- assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
+ assert(nm->insts_contains_inclusive(original_pc),
+ "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
}
#endif
diff --git a/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp b/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp
index 589d75be640..4bde8e7be08 100644
--- a/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp
+++ b/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp
@@ -75,7 +75,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
- assert(_cb->as_compiled_method()->insts_contains(_pc), "original PC must be in CompiledMethod");
+ assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
+ "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
diff --git a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp
index 1aa158b4a8f..3562a79825f 100644
--- a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -741,7 +741,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Register tmp = R14;
Register tmp2 = R15;
- Label refill, restart;
+ Label refill, restart, marking_not_active;
+ int satb_q_active_byte_offset =
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ SATBMarkQueue::byte_offset_of_active());
int satb_q_index_byte_offset =
in_bytes(JavaThread::satb_mark_queue_offset() +
SATBMarkQueue::byte_offset_of_index());
@@ -753,6 +756,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
__ std(tmp, -16, R1_SP);
__ std(tmp2, -24, R1_SP);
+ // Is marking still active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ lwz(tmp, satb_q_active_byte_offset, R16_thread);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ lbz(tmp, satb_q_active_byte_offset, R16_thread);
+ }
+ __ cmpdi(CCR0, tmp, 0);
+ __ beq(CCR0, marking_not_active);
+
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate.
@@ -769,6 +782,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
__ std(tmp, satb_q_index_byte_offset, R16_thread);
__ stdx(pre_val, tmp2, tmp); // [_buf + index] :=
+ __ bind(marking_not_active);
// Restore temp registers and return-from-leaf.
__ ld(tmp2, -24, R1_SP);
__ ld(tmp, -16, R1_SP);
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
index 2d1f0c7230b..a5d5613a414 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
@@ -2569,7 +2569,7 @@ void MacroAssembler::rtm_retry_lock_on_abort(Register retry_count_Reg, Register
}
// Spin and retry if lock is busy.
-// inputs: box_Reg (monitor address)
+// inputs: owner_addr_Reg (monitor address)
// : retry_count_Reg
// output: retry_count_Reg decremented by 1
// CTR is killed
@@ -2577,15 +2577,22 @@ void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register o
Label SpinLoop, doneRetry;
addic_(retry_count_Reg, retry_count_Reg, -1);
blt(CCR0, doneRetry);
- li(R0, RTMSpinLoopCount);
- mtctr(R0);
+
+ if (RTMSpinLoopCount > 1) {
+ li(R0, RTMSpinLoopCount);
+ mtctr(R0);
+ }
bind(SpinLoop);
smt_yield(); // Can't use waitrsv(). No permission (SIGILL).
- bdz(retryLabel);
- ld(R0, 0, owner_addr_Reg);
- cmpdi(CCR0, R0, 0);
- bne(CCR0, SpinLoop);
+
+ if (RTMSpinLoopCount > 1) {
+ bdz(retryLabel);
+ ld(R0, 0, owner_addr_Reg);
+ cmpdi(CCR0, R0, 0);
+ bne(CCR0, SpinLoop);
+ }
+
b(retryLabel);
bind(doneRetry);
diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp
index 6c6b83d257f..5e8be1425fa 100644
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp
@@ -327,7 +327,10 @@ void VM_Version::initialize() {
warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50");
FLAG_SET_DEFAULT(RTMAbortRatio, 50);
}
- guarantee(RTMSpinLoopCount > 0, "unsupported");
+ if (RTMSpinLoopCount < 0) {
+ warning("RTMSpinLoopCount must not be a negative value, resetting it to 0");
+ FLAG_SET_DEFAULT(RTMSpinLoopCount, 0);
+ }
#else
// Only C2 does RTM locking optimization.
// Can't continue because UseRTMLocking affects UseBiasedLocking flag
diff --git a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp
index 524a91fe07f..84fb4205099 100644
--- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp
@@ -1105,16 +1105,16 @@ void LIR_Assembler::reg2mem(LIR_Opr from, LIR_Opr dest_opr, BasicType type,
}
case T_FLOAT :
if (short_disp) {
- __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest);
+ __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest);
} else {
- __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest);
+ __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest);
}
break;
case T_DOUBLE:
if (short_disp) {
- __ z_std(from->as_double_reg(), disp_value, disp_reg, dest);
+ __ z_std(from->as_double_reg(), disp_value, disp_reg, dest);
} else {
- __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest);
+ __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest);
}
break;
default: ShouldNotReachHere();
@@ -1148,6 +1148,10 @@ void LIR_Assembler::return_op(LIR_Opr result) {
__ restore_return_pc();
}
+ if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
+ __ reserved_stack_check(Z_R14);
+ }
+
// We need to mark the code position where the load from the safepoint
// polling page was emitted as relocInfo::poll_return_type here.
__ relocate(relocInfo::poll_return_type);
diff --git a/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp b/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp
index c0fbee53da7..7b65476212f 100644
--- a/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -784,7 +784,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val.
Register tmp2 = Z_R7;
- Label refill, restart;
+ Label refill, restart, marking_not_active;
+ int satb_q_active_byte_offset =
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ SATBMarkQueue::byte_offset_of_active());
int satb_q_index_byte_offset =
in_bytes(JavaThread::satb_mark_queue_offset() +
SATBMarkQueue::byte_offset_of_index());
@@ -796,6 +799,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
__ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
+ // Is marking still active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset));
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset));
+ }
+ __ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently.
+
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate.
@@ -810,6 +822,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
__ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] :=
__ z_stg(tmp, satb_q_index_byte_offset, Z_thread);
+ __ bind(marking_not_active);
// Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()).
__ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
diff --git a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp
index 83261cfdf47..63a9cb5abef 100644
--- a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp
+++ b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp
@@ -52,4 +52,6 @@ const bool CCallingConventionRequiresIntsAsLongs = true;
// The expected size in bytes of a cache line, used to pad data structures.
#define DEFAULT_CACHE_LINE_SIZE 256
+#define SUPPORT_RESERVED_STACK_AREA
+
#endif // CPU_S390_VM_GLOBALDEFINITIONS_S390_HPP
diff --git a/hotspot/src/cpu/s390/vm/globals_s390.hpp b/hotspot/src/cpu/s390/vm/globals_s390.hpp
index fcd3ff45227..cb5adff3ef5 100644
--- a/hotspot/src/cpu/s390/vm/globals_s390.hpp
+++ b/hotspot/src/cpu/s390/vm/globals_s390.hpp
@@ -56,7 +56,7 @@ define_pd_global(intx, InlineSmallCode, 2000);
// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the
// stack. To pass stack overflow tests we need 20 shadow pages.
#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+2))
-#define DEFAULT_STACK_RESERVED_PAGES (0)
+#define DEFAULT_STACK_RESERVED_PAGES (1)
#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
diff --git a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp
index c53fa419a27..8cec2da25ac 100644
--- a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp
@@ -860,16 +860,39 @@ void InterpreterMacroAssembler::remove_activation(TosState state,
bool throw_monitor_exception,
bool install_monitor_exception,
bool notify_jvmti) {
-
+ BLOCK_COMMENT("remove_activation {");
unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception);
// Save result (push state before jvmti call and pop it afterwards) and notify jvmti.
notify_method_exit(false, state, notify_jvmti ? NotifyJVMTI : SkipNotifyJVMTI);
+ if (StackReservedPages > 0) {
+ BLOCK_COMMENT("reserved_stack_check:");
+ // Test if reserved zone needs to be enabled.
+ Label no_reserved_zone_enabling;
+
+ // Compare frame pointers. There is no good stack pointer, as with stack
+ // frame compression we can get different SPs when we do calls. A subsequent
+ // call could have a smaller SP, so that this compare succeeds for an
+ // inner call of the method annotated with ReservedStack.
+ z_lg(Z_R0, Address(Z_SP, (intptr_t)_z_abi(callers_sp)));
+ z_clg(Z_R0, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); // Compare with frame pointer in memory.
+ z_brl(no_reserved_zone_enabling);
+
+ // Enable reserved zone again, throw stack overflow exception.
+ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread);
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError));
+
+ should_not_reach_here();
+
+ bind(no_reserved_zone_enabling);
+ }
+
verify_oop(Z_tos, state);
verify_thread();
pop_interpreter_frame(return_pc, Z_ARG2, Z_ARG3);
+ BLOCK_COMMENT("} remove_activation");
}
// lock object
diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp
index a7cbd706255..0f78e5a6250 100644
--- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp
@@ -2666,6 +2666,32 @@ void MacroAssembler::bang_stack_with_offset(int offset) {
}
}
+void MacroAssembler::reserved_stack_check(Register return_pc) {
+ // Test if reserved zone needs to be enabled.
+ Label no_reserved_zone_enabling;
+ assert(return_pc == Z_R14, "Return pc must be in R14 before z_br() to StackOverflow stub.");
+ BLOCK_COMMENT("reserved_stack_check {");
+
+ z_clg(Z_SP, Address(Z_thread, JavaThread::reserved_stack_activation_offset()));
+ z_brl(no_reserved_zone_enabling);
+
+ // Enable reserved zone again, throw stack overflow exception.
+ save_return_pc();
+ push_frame_abi160(0);
+ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread);
+ pop_frame();
+ restore_return_pc();
+
+ load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry());
+ // Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc.
+ z_br(Z_R1);
+
+ should_not_reach_here();
+
+ bind(no_reserved_zone_enabling);
+ BLOCK_COMMENT("} reserved_stack_check");
+}
+
// Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes.
void MacroAssembler::tlab_allocate(Register obj,
Register var_size_in_bytes,
diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp
index c9540860958..588bde6207e 100644
--- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp
+++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp
@@ -627,6 +627,11 @@ class MacroAssembler: public Assembler {
// Stack overflow checking
void bang_stack_with_offset(int offset);
+ // Check for reserved stack access in method being exited. If the reserved
+ // stack area was accessed, protect it again and throw StackOverflowError.
+ // Uses Z_R1.
+ void reserved_stack_check(Register return_pc);
+
// Atomics
// -- none?
diff --git a/hotspot/src/cpu/s390/vm/s390.ad b/hotspot/src/cpu/s390/vm/s390.ad
index 8ab6a5026d3..fd188525c46 100644
--- a/hotspot/src/cpu/s390/vm/s390.ad
+++ b/hotspot/src/cpu/s390/vm/s390.ad
@@ -909,15 +909,8 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
// If this does safepoint polling, then do it here.
bool need_polling = do_polling() && C->is_method_compilation();
- // Touch the polling page.
- // Part 1: get the page's address.
- if (need_polling) {
- AddressLiteral pp(os::get_polling_page());
- __ load_const_optimized(Z_R1_scratch, pp);
- }
-
// Pop frame, restore return_pc, and all stuff needed by interpreter.
- // Pop frame by add insted of load (a penny saved is a penny got :-).
+ // Pop frame by add instead of load (a penny saved is a penny got :-).
int frame_size_in_bytes = Assembler::align((C->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes);
int retPC_offset = frame_size_in_bytes + _z_abi16(return_pc);
if (Displacement::is_validDisp(retPC_offset)) {
@@ -928,9 +921,14 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
__ restore_return_pc();
}
- // Touch the polling page,
- // part 2: touch the page now.
+ if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
+ __ reserved_stack_check(Z_R14);
+ }
+
+ // Touch the polling page.
if (need_polling) {
+ AddressLiteral pp(os::get_polling_page());
+ __ load_const_optimized(Z_R1_scratch, pp);
// We need to mark the code position where the load from the safepoint
// polling page was emitted as relocInfo::poll_return_type here.
__ relocate(relocInfo::poll_return_type);
@@ -939,7 +937,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
}
uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
- // variable size. determine dynamically.
+ // Variable size. determine dynamically.
return MachNode::size(ra_);
}
diff --git a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp
index 8b872c5c922..be107222636 100644
--- a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp
@@ -2433,13 +2433,12 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_throw_StackOverflowError_entry =
generate_throw_exception("StackOverflowError throw_exception",
CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
+ StubRoutines::_throw_delayed_StackOverflowError_entry =
+ generate_throw_exception("delayed StackOverflowError throw_exception",
+ CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false);
//----------------------------------------------------------------------
// Entry points that are platform specific.
- // Build this early so it's available for the interpreter.
- StubRoutines::_throw_StackOverflowError_entry =
- generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
if (UseCRC32Intrinsics) {
// We have no CRC32 table on z/Architecture.
diff --git a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp
index de266db04fc..2084f36006f 100644
--- a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp
+++ b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp
@@ -1112,16 +1112,21 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
// top_frame_size = TOP_IJAVA_FRAME_ABI + max_stack + size of interpreter state
__ add2reg(top_frame_size,
frame::z_top_ijava_frame_abi_size +
- frame::z_ijava_state_size +
- frame::interpreter_frame_monitor_size() * wordSize,
+ frame::z_ijava_state_size +
+ frame::interpreter_frame_monitor_size() * wordSize,
max_stack);
- // Check if there's room for the new frame...
- Register frame_size = max_stack; // Reuse the regiser for max_stack.
- __ z_lgr(frame_size, Z_SP);
- __ z_sgr(frame_size, sp_after_resize);
- __ z_agr(frame_size, top_frame_size);
- generate_stack_overflow_check(frame_size, fp/*tmp1*/);
+ if (!native_call) {
+ // Stack overflow check.
+ // Native calls don't need the stack size check since they have no
+ // expression stack and the arguments are already on the stack and
+ // we only add a handful of words to the stack.
+ Register frame_size = max_stack; // Reuse the regiser for max_stack.
+ __ z_lgr(frame_size, Z_SP);
+ __ z_sgr(frame_size, sp_after_resize);
+ __ z_agr(frame_size, top_frame_size);
+ generate_stack_overflow_check(frame_size, fp/*tmp1*/);
+ }
DEBUG_ONLY(__ z_cg(Z_R14, _z_abi16(return_pc), Z_SP));
__ asm_assert_eq("killed Z_R14", 0);
diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
index 97fb2745a26..ae2942f19b5 100644
--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -694,6 +694,7 @@ void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) {
int store_offset;
if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) {
+ assert(base != O7, "destroying register");
assert(!unaligned, "can't handle this");
// for offsets larger than a simm13 we setup the offset in O7
__ set(offset, O7);
@@ -712,9 +713,12 @@ int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType
case T_LONG :
#ifdef _LP64
if (unaligned || PatchALot) {
- __ srax(from_reg->as_register_lo(), 32, O7);
+ // Don't use O7 here because it may be equal to 'base' (see LIR_Assembler::reg2mem)
+ assert(G3_scratch != base, "can't handle this");
+ assert(G3_scratch != from_reg->as_register_lo(), "can't handle this");
+ __ srax(from_reg->as_register_lo(), 32, G3_scratch);
__ stw(from_reg->as_register_lo(), base, offset + lo_word_offset_in_bytes);
- __ stw(O7, base, offset + hi_word_offset_in_bytes);
+ __ stw(G3_scratch, base, offset + hi_word_offset_in_bytes);
} else {
__ stx(from_reg->as_register_lo(), base, offset);
}
@@ -821,7 +825,7 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ
case T_SHORT : __ ldsh(base, offset, to_reg->as_register()); break;
case T_INT : __ ld(base, offset, to_reg->as_register()); break;
case T_LONG :
- if (!unaligned) {
+ if (!unaligned && !PatchALot) {
#ifdef _LP64
__ ldx(base, offset, to_reg->as_register_lo());
#else
@@ -1297,7 +1301,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type,
disp_reg = O7;
}
} else if (unaligned || PatchALot) {
- __ add(src, addr->index()->as_register(), O7);
+ __ add(src, addr->index()->as_pointer_register(), O7);
src = O7;
} else {
disp_reg = addr->index()->as_pointer_register();
@@ -1424,7 +1428,7 @@ void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type,
disp_reg = O7;
}
} else if (unaligned || PatchALot) {
- __ add(src, addr->index()->as_register(), O7);
+ __ add(src, addr->index()->as_pointer_register(), O7);
src = O7;
} else {
disp_reg = addr->index()->as_pointer_register();
diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp
index 5530a85cb4c..40e30551967 100644
--- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -856,7 +856,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Register tmp2 = G3_scratch;
Label refill, restart;
- bool with_frame = false; // I don't know if we can do with-frame.
+ int satb_q_active_byte_offset =
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ SATBMarkQueue::byte_offset_of_active());
int satb_q_index_byte_offset =
in_bytes(JavaThread::satb_mark_queue_offset() +
SATBMarkQueue::byte_offset_of_index());
@@ -864,6 +866,17 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
in_bytes(JavaThread::satb_mark_queue_offset() +
SATBMarkQueue::byte_offset_of_buf());
+ // Is marking still active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ ld(G2_thread, satb_q_active_byte_offset, tmp);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ ldsb(G2_thread, satb_q_active_byte_offset, tmp);
+ }
+ __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart);
+ __ retl();
+ __ delayed()->nop();
+
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate
diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp
index 5fe455600d1..58db92dcd32 100644
--- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1623,6 +1623,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
NOT_LP64(__ get_thread(thread);)
+ Address queue_active(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
+ SATBMarkQueue::byte_offset_of_active()));
Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
SATBMarkQueue::byte_offset_of_index()));
Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
@@ -1631,6 +1633,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Label done;
Label runtime;
+ // Is marking still active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ cmpl(queue_active, 0);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ cmpb(queue_active, 0);
+ }
+ __ jcc(Assembler::equal, done);
+
// Can we store original value in the thread's buffer?
__ movptr(tmp, queue_index);
diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp
index 9cbc29af4c9..11f28bdb6ca 100644
--- a/hotspot/src/cpu/x86/vm/frame_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp
@@ -376,7 +376,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
fr._unextended_sp = unextended_sp;
address original_pc = nm->get_original_pc(&fr);
- assert(nm->insts_contains(original_pc), "original PC must be in CompiledMethod");
+ assert(nm->insts_contains_inclusive(original_pc),
+ "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
}
#endif
diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp
index d7d8e47ea89..d0c72947e0f 100644
--- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp
+++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp
@@ -75,7 +75,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
- assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod");
+ assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
+ "original PC must be in the main code section of the the compiled method (or must be immediately following it)");
_deopt_state = is_deoptimized;
} else {
if (_cb->is_deoptimization_stub()) {
diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
index 3d4dee751a5..b6d32631582 100644
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
@@ -3499,12 +3499,12 @@ void MacroAssembler::movdqu(XMMRegister dst, XMMRegister src) {
}
}
-void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src) {
+void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg) {
if (reachable(src)) {
movdqu(dst, as_Address(src));
} else {
- lea(rscratch1, src);
- movdqu(dst, Address(rscratch1, 0));
+ lea(scratchReg, src);
+ movdqu(dst, Address(scratchReg, 0));
}
}
diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp
index 02fb401511e..a3e81e58dc5 100644
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp
@@ -1085,7 +1085,7 @@ public:
void movdqu(Address dst, XMMRegister src);
void movdqu(XMMRegister dst, Address src);
void movdqu(XMMRegister dst, XMMRegister src);
- void movdqu(XMMRegister dst, AddressLiteral src);
+ void movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg = rscratch1);
// AVX Unaligned forms
void vmovdqu(Address dst, XMMRegister src);
void vmovdqu(XMMRegister dst, Address src);
diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp
index 37d93a48f21..10935345f70 100644
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp
@@ -817,7 +817,7 @@ enum {
movl(d, Address(CTX, 4*3));
movl(e, Address(CTX, 4*4));
movl(f, Address(CTX, 4*5));
- movl(g, Address(CTX, 4*6));
+ // load g - r10 after it is used as scratch
movl(h, Address(CTX, 4*7));
pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask;
@@ -825,6 +825,8 @@ enum {
vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip]
vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip]
+ movl(g, Address(CTX, 4*6));
+
movq(Address(rsp, _CTX), CTX); // store
bind(loop0);
@@ -977,7 +979,7 @@ bind(only_one_block);
movl(d, Address(CTX, 4*3)); // 0xa54ff53a
movl(e, Address(CTX, 4*4)); // 0x510e527f
movl(f, Address(CTX, 4*5)); // 0x9b05688c
- movl(g, Address(CTX, 4*6)); // 0x1f83d9ab
+ // load g - r10 after use as scratch
movl(h, Address(CTX, 4*7)); // 0x5be0cd19
@@ -986,6 +988,8 @@ bind(only_one_block);
vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip]
vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip]
+ movl(g, Address(CTX, 4*6)); // 0x1f83d9ab
+
movq(Address(rsp, _CTX), CTX);
jmpb(do_last_block);
@@ -1154,9 +1158,8 @@ void MacroAssembler::sha512_AVX2_one_round_and_schedule(
// Move to appropriate lanes for calculating w[16] and w[17]
vperm2f128(xmm4, xmm0, xmm0, 0); //xmm4 = W[-16] + W[-7] + s0{ BABA }
- address MASK_YMM_LO = StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512();
//Move to appropriate lanes for calculating w[18] and w[19]
- vpand(xmm0, xmm0, ExternalAddress(MASK_YMM_LO + 32), AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 }
+ vpand(xmm0, xmm0, xmm10, AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 }
//Calculate w[16] and w[17] in both 128 bit lanes
//Calculate sigma1 for w[16] and w[17] on both 128 bit lanes
vperm2f128(xmm2, xmm7, xmm7, 17); //xmm2 = W[-2] {BABA}
@@ -1250,6 +1253,7 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste
const XMMRegister& XFER = xmm0; // YTMP0
const XMMRegister& BYTE_FLIP_MASK = xmm9; // ymm9
+ const XMMRegister& YMM_MASK_LO = xmm10; // ymm10
#ifdef _WIN64
const Register& INP = rcx; //1st arg
const Register& CTX = rdx; //2nd arg
@@ -1368,11 +1372,14 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste
movq(d, Address(CTX, 8 * 3));
movq(e, Address(CTX, 8 * 4));
movq(f, Address(CTX, 8 * 5));
- movq(g, Address(CTX, 8 * 6));
+ // load g - r10 after it is used as scratch
movq(h, Address(CTX, 8 * 7));
pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask_sha512;
vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); //PSHUFFLE_BYTE_FLIP_MASK wrt rip
+ vmovdqu(YMM_MASK_LO, ExternalAddress(pshuffle_byte_flip_mask_addr + 32));
+
+ movq(g, Address(CTX, 8 * 6));
bind(loop0);
lea(TBL, ExternalAddress(K512_W));
diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
index 1853cf9a42a..48be33ae526 100644
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
@@ -3207,7 +3207,7 @@ class StubGenerator: public StubCodeGenerator {
const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16)
#else
const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64
- const Register len_reg = r10; // pick the first volatile windows register
+ const Register len_reg = r11; // pick the volatile windows register
#endif
const Register pos = rax;
@@ -3404,7 +3404,7 @@ class StubGenerator: public StubCodeGenerator {
const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16)
#else
const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64
- const Register len_reg = r10; // pick the first volatile windows register
+ const Register len_reg = r11; // pick the volatile windows register
#endif
const Register pos = rax;
@@ -3930,7 +3930,7 @@ class StubGenerator: public StubCodeGenerator {
__ push(rbx); // Save RBX
__ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter
- __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()));
+ __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()), pos); // pos as scratch
__ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled
__ movptr(pos, 0);
@@ -3953,7 +3953,7 @@ class StubGenerator: public StubCodeGenerator {
__ movl(Address(used_addr, 0), used);
// key length could be only {11, 13, 15} * 4 = {44, 52, 60}
- __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()), rbx); // rbx as scratch
__ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
__ cmpl(rbx, 52);
__ jcc(Assembler::equal, L_multiBlock_loopTop[1]);
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
index 7be7a80192e..6cd7a4ad8b0 100644
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
@@ -37,6 +37,7 @@ import jdk.tools.jaotc.binformat.Symbol.Binding;
import jdk.tools.jaotc.binformat.Symbol.Kind;
import jdk.tools.jaotc.binformat.elf.JELFRelocObject;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
/**
* A format-agnostic container class that holds various components of a binary.
@@ -257,9 +258,9 @@ public class BinaryContainer implements SymbolTable {
* prefix {@code prefix}. It also initializes internal code container, symbol table and
* relocation tables.
*/
- public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) {
- this.codeSegmentSize = config.codeSegmentSize;
- this.codeEntryAlignment = config.codeEntryAlignment;
+ public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
+ this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
+ this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
// read only, code
codeContainer = new CodeContainer(".text", this);
@@ -289,30 +290,31 @@ public class BinaryContainer implements SymbolTable {
addGlobalSymbols();
- recordConfiguration(config);
+ recordConfiguration(graalHotSpotVMConfig, graphBuilderConfig);
}
- private void recordConfiguration(GraalHotSpotVMConfig config) {
+ private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig) {
// @formatter:off
- boolean[] booleanFlags = { config.cAssertions, // Debug VM
- config.useCompressedOops,
- config.useCompressedClassPointers,
- config.compactFields,
- config.useG1GC,
- config.useCMSGC,
- config.useTLAB,
- config.useBiasedLocking,
+ boolean[] booleanFlags = { graalHotSpotVMConfig.cAssertions, // Debug VM
+ graalHotSpotVMConfig.useCompressedOops,
+ graalHotSpotVMConfig.useCompressedClassPointers,
+ graalHotSpotVMConfig.compactFields,
+ graalHotSpotVMConfig.useG1GC,
+ graalHotSpotVMConfig.useCMSGC,
+ graalHotSpotVMConfig.useTLAB,
+ graalHotSpotVMConfig.useBiasedLocking,
TieredAOT.getValue(),
- config.enableContended,
- config.restrictContended,
+ graalHotSpotVMConfig.enableContended,
+ graalHotSpotVMConfig.restrictContended,
+ graphBuilderConfig.omitAssertions()
};
- int[] intFlags = { config.narrowOopShift,
- config.narrowKlassShift,
- config.contendedPaddingWidth,
- config.fieldsAllocationStyle,
- config.objectAlignment,
- config.codeSegmentSize,
+ int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift,
+ graalHotSpotVMConfig.getKlassEncoding().shift,
+ graalHotSpotVMConfig.contendedPaddingWidth,
+ graalHotSpotVMConfig.fieldsAllocationStyle,
+ 1 << graalHotSpotVMConfig.getOopEncoding().alignment,
+ graalHotSpotVMConfig.codeSegmentSize,
};
// @formatter:on
@@ -395,6 +397,10 @@ public class BinaryContainer implements SymbolTable {
return "_aot_narrow_klass_base_address";
}
+ public String getNarrowOopBaseAddressSymbolName() {
+ return "_aot_narrow_oop_base_address";
+ }
+
public String getLogOfHeapRegionGrainBytesSymbolName() {
return "_aot_log_of_heap_region_grain_bytes";
}
@@ -445,6 +451,7 @@ public class BinaryContainer implements SymbolTable {
createGotSymbol(getHeapTopAddressSymbolName());
createGotSymbol(getHeapEndAddressSymbolName());
createGotSymbol(getNarrowKlassBaseAddressSymbolName());
+ createGotSymbol(getNarrowOopBaseAddressSymbolName());
createGotSymbol(getPollingPageSymbolName());
createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName());
createGotSymbol(getInlineContiguousAllocationSupportedSymbolName());
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
index b5d081a51ca..3ba1067b959 100644
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
@@ -77,10 +77,14 @@ public class AOTBackend {
this.filters = filters;
providers = backend.getProviders();
codeCache = providers.getCodeCache();
- graphBuilderSuite = initGraphBuilderSuite(backend);
+ graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions);
highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL);
}
+ public PhaseSuite getGraphBuilderSuite() {
+ return graphBuilderSuite;
+ }
+
private Suites getSuites() {
// create suites every time, as we modify options for the compiler
return backend.getSuites().getDefaultSuites();
@@ -146,14 +150,14 @@ public class AOTBackend {
return backend.getRuntime().getVMConfig().cAssertions;
}
- private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend) {
+ private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) {
PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
// Use all default plugins.
Plugins plugins = baseConfig.getPlugins();
- GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+ GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withOmitAssertions(!compileWithAssertions);
iterator.next();
iterator.remove();
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java
index cbf26294b0d..68fb146b8ce 100644
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java
@@ -293,12 +293,18 @@ public class AOTCompiledClass {
// Record methods holder
methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType);
// Record inlinee classes
- for (ResolvedJavaMethod m : methodInfo.getCompilationResult().getMethods()) {
- methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
+ ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods();
+ if (inlinees != null) {
+ for (ResolvedJavaMethod m : inlinees) {
+ methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
+ }
}
// Record classes of fields that were accessed
- for (ResolvedJavaField f : methodInfo.getCompilationResult().getFields()) {
- methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
+ ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields();
+ if (fields != null) {
+ for (ResolvedJavaField f : fields) {
+ methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
+ }
}
}
}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java
new file mode 100644
index 00000000000..a0a01f7c1c9
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java
@@ -0,0 +1,64 @@
+package jdk.tools.jaotc;/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public class LoadedClass {
+ private final String name;
+ private final Class> clz;
+
+ public LoadedClass(String name, Class> clz) {
+ this.name = name;
+ this.clz = clz;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Class> getLoadedClass() {
+ return clz;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof LoadedClass)) return false;
+
+ LoadedClass that = (LoadedClass) o;
+
+ if (name != null ? !name.equals(that.name) : that.name != null) return false;
+ return clz != null ? clz.equals(that.clz) : that.clz == null;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name != null ? name.hashCode() : 0;
+ result = 31 * result + (clz != null ? clz.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
index a1257b7a013..a98dc8d2d81 100644
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,19 +43,31 @@ import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.Set;
import java.util.stream.Stream;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ByteContainer;
-import jdk.tools.jaotc.collect.ClassCollector;
+import jdk.tools.jaotc.collect.*;
+import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
import jdk.tools.jaotc.utils.Timer;
import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.runtime.RuntimeProvider;
import jdk.vm.ci.meta.MetaAccessProvider;
@@ -120,17 +132,7 @@ public class Main implements LogPrinter {
abstract void process(Main task, String opt, String arg) throws BadArgs;
}
- static Option[] recognizedOptions = {new Option(" --module Module to compile", true, "--module") {
- @Override
- void process(Main task, String opt, String arg) {
- task.options.module = arg;
- }
- }, new Option(" --module-path Specify where to find module to compile", true, "--module-path") {
- @Override
- void process(Main task, String opt, String arg) {
- task.options.modulepath = arg;
- }
- }, new Option(" --output Output file name", true, "--output") {
+ static Option[] recognizedOptions = { new Option(" --output Output file name", true, "--output") {
@Override
void process(Main task, String opt, String arg) {
String name = arg;
@@ -139,22 +141,48 @@ public class Main implements LogPrinter {
}
task.options.outputName = name;
}
+ }, new Option(" --class-name List of classes to compile", true, "--class-name", "--classname") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg));
+ }
+ }, new Option(" --jar List of jar files to compile", true, "--jar") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg));
+ }
+ }, new Option(" --module List of modules to compile", true, "--module") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg));
+ }
+ }, new Option(" --directory List of directories where to search for files to compile", true, "--directory") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg));
+ }
+ }, new Option(" --search-path List of directories where to search for specified files", true, "--search-path") {
+ @Override
+ void process(Main task, String opt, String arg) {
+ String[] elements = arg.split(":");
+ task.options.searchPath.add(elements);
+ }
}, new Option(" --compile-commands Name of file with compile commands", true, "--compile-commands") {
@Override
void process(Main task, String opt, String arg) {
task.options.methodList = arg;
}
- }, new Option(" --compile-for-tiered Generated profiling code for tiered compilation", false, "--compile-for-tiered") {
+ }, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
@Override
void process(Main task, String opt, String arg) {
TieredAOT.setValue(true);
}
- }, new Option(" --classpath Specify where to find user class files", true, "--classpath", "--class-path") {
+ }, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") {
@Override
void process(Main task, String opt, String arg) {
- task.options.classpath = arg;
+ task.options.compileWithAssertions = true;
}
- }, new Option(" --threads Number of compilation threads to be used", true, "--threads") {
+ }, new Option(" --compile-threads Number of compilation threads to be used", true, "--compile-threads", "--threads") {
@Override
void process(Main task, String opt, String arg) {
int threads = Integer.parseInt(arg);
@@ -213,27 +241,27 @@ public class Main implements LogPrinter {
}};
public static class Options {
- public List files = new LinkedList<>();
- public String module = null;
- public String modulepath = "modules";
+ public List files = new LinkedList<>();
public String outputName = "unnamed";
public String methodList;
- public String classpath = ".";
+ public List sources = new ArrayList<>();
+ public SearchPath searchPath = new SearchPath();
/**
* We don't see scaling beyond 16 threads.
*/
private static final int COMPILER_THREADS = 16;
- int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
+ public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
public boolean ignoreClassLoadingErrors;
public boolean exitOnError;
- boolean info;
- boolean verbose;
- boolean debug;
- boolean help;
- boolean version;
+ public boolean info;
+ public boolean verbose;
+ public boolean debug;
+ public boolean help;
+ public boolean version;
+ public boolean compileWithAssertions;
}
/* package */final Options options = new Options();
@@ -275,7 +303,9 @@ public class Main implements LogPrinter {
printlnInfo("Compiling " + options.outputName + "...");
final long start = System.currentTimeMillis();
- run();
+ if (!run()) {
+ return EXIT_ABNORMAL;
+ }
final long end = System.currentTimeMillis();
printlnInfo("Total time: " + (end - start) + " ms");
@@ -318,17 +348,34 @@ public class Main implements LogPrinter {
}
@SuppressWarnings("try")
- private void run() throws Exception {
+ private boolean run() throws Exception {
openLog();
try {
CompilationSpec compilationRestrictions = collectSpecifiedMethods();
- Set> classesToCompile;
+ Set> classesToCompile = new HashSet<>();
try (Timer t = new Timer(this, "")) {
- ClassCollector collector = new ClassCollector(this.options, this);
- classesToCompile = collector.collectClassesToCompile();
+ FileSupport fileSupport = new FileSupport();
+ ClassSearch lookup = new ClassSearch();
+ lookup.addProvider(new ModuleSourceProvider());
+ lookup.addProvider(new ClassNameSourceProvider(fileSupport));
+ lookup.addProvider(new JarSourceProvider());
+ lookup.addProvider(new DirectorySourceProvider(fileSupport));
+
+ List found = null;
+ try {
+ found = lookup.search(options.files, options.searchPath);
+ } catch (InternalError e) {
+ reportError(e);
+ return false;
+ }
+
+ for (LoadedClass loadedClass : found) {
+ classesToCompile.add(loadedClass.getLoadedClass());
+ }
+
printInfo(classesToCompile.size() + " classes found");
}
@@ -356,6 +403,11 @@ public class Main implements LogPrinter {
AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads);
classes = compiler.compileClasses(classes);
+ GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig();
+ PhaseSuite graphBuilderSuite = aotBackend.getGraphBuilderSuite();
+ ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
+ GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
+
// Free memory!
try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
printMemoryUsage();
@@ -364,7 +416,7 @@ public class Main implements LogPrinter {
System.gc();
}
- BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION);
+ BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
dataBuilder.prepareData();
@@ -446,6 +498,7 @@ public class Main implements LogPrinter {
} finally {
closeLog();
}
+ return true;
}
private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) {
@@ -509,7 +562,7 @@ public class Main implements LogPrinter {
break;
}
} else {
- options.files.add(arg);
+ options.files.add(new SearchFor(arg));
}
}
}
@@ -570,6 +623,12 @@ public class Main implements LogPrinter {
log.flush();
}
+ private void reportError(Throwable e) {
+ log.println("Error: " + e.getMessage());
+ e.printStackTrace(log);
+ log.flush();
+ }
+
private void reportError(String key, Object... args) {
printError(MessageFormat.format(key, args));
}
@@ -580,17 +639,17 @@ public class Main implements LogPrinter {
}
private void showUsage() {
- log.println("Usage: " + PROGNAME + " list...");
+ log.println("Usage: " + PROGNAME + " list");
log.println("use --help for a list of possible options");
}
private void showHelp() {
- log.println("Usage: " + PROGNAME + " <--module name> | ");
+ log.println("Usage: " + PROGNAME + " list");
log.println();
- log.println(" list A list of class files, jar files or directories which");
- log.println(" contains class files.");
+ log.println(" list A : separated list of class names, modules, jar files");
+ log.println(" or directories which contain class files.");
log.println();
- log.println("where possible options include:");
+ log.println("where options include:");
for (Option o : recognizedOptions) {
String name = o.aliases[0].substring(1); // there must always be at least one name
name = name.charAt(0) == '-' ? name.substring(1) : name;
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java
index 4bbd4665434..eedeac3b720 100644
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java
@@ -48,6 +48,7 @@ enum MarkId {
HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"),
HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"),
NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"),
+ NARROW_OOP_BASE_ADDRESS("CodeInstaller::NARROW_OOP_BASE_ADDRESS"),
CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"),
LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"),
INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED");
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
index 1e1944bc274..7a833c13914 100644
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
@@ -57,6 +57,7 @@ class MarkProcessor {
case HEAP_TOP_ADDRESS:
case HEAP_END_ADDRESS:
case NARROW_KLASS_BASE_ADDRESS:
+ case NARROW_OOP_BASE_ADDRESS:
case CRC_TABLE_ADDRESS:
case LOG_OF_HEAP_REGION_GRAIN_BYTES:
case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
@@ -78,6 +79,9 @@ class MarkProcessor {
case NARROW_KLASS_BASE_ADDRESS:
vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName();
break;
+ case NARROW_OOP_BASE_ADDRESS:
+ vmSymbolName = binaryContainer.getNarrowOopBaseAddressSymbolName();
+ break;
case CRC_TABLE_ADDRESS:
vmSymbolName = binaryContainer.getCrcTableAddressSymbolName();
break;
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java
deleted file mode 100644
index c46b3bfd062..00000000000
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.tools.jaotc.collect;
-
-import jdk.tools.jaotc.LogPrinter;
-import jdk.tools.jaotc.Main;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.*;
-import java.nio.file.*;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.*;
-
-import static java.nio.file.FileVisitResult.CONTINUE;
-
-public class ClassCollector {
- private final Main.Options options;
- private final LogPrinter log;
-
- public ClassCollector(Main.Options options, LogPrinter log) {
- this.options = options;
- this.log = log;
- }
-
- /**
- * Collect all class names passed by the user.
- *
- * @return array list of classes
- */
- public Set> collectClassesToCompile() {
- Set> classes = new HashSet<>();
- List filesToScan = new LinkedList<>(options.files);
-
- if (options.module != null) {
- classes.addAll(scanModule(filesToScan));
- }
-
- classes.addAll(scanFiles(filesToScan));
- return classes;
- }
-
- private Set> scanModule(List filesToScan) {
- String module = options.module;
- // Search module in standard JDK installation.
- Path dir = getModuleDirectory(options.modulepath, module);
-
- if (Files.isDirectory(dir)) {
- return loadFromModuleDirectory(dir);
- } else {
- findFilesToScan(filesToScan, module);
- return new HashSet<>();
- }
- }
-
- private Set> loadFromModuleDirectory(Path dir) {
- log.printInfo("Scanning module: " + dir + " ...");
- log.printlnVerbose(" "); // Break line
-
- FileSystemFinder finder = new FileSystemFinder(dir, pathname -> entryIsClassFile(pathname.toString()));
- Set> cls = loadWithClassLoader(() -> ClassLoader.getSystemClassLoader(), dir, finder);
- log.printlnInfo(" " + cls.size() + " classes loaded.");
- return cls;
- }
-
- private void findFilesToScan(List filesToScan, String module) {
- // Try to search regular directory, .jar or .class files
- Path path = Paths.get(options.modulepath, module);
-
- if (Files.isDirectory(path)) {
- filesToScan.add(".");
- options.classpath = path.toString();
- } else if (path.endsWith(".jar") || path.endsWith(".class")) {
- filesToScan.add(path.toString());
- } else {
- path = Paths.get(options.modulepath, module + ".jar");
- if (Files.exists(path)) {
- filesToScan.add(path.toString());
- } else {
- path = Paths.get(options.modulepath, module + ".class");
- if (Files.exists(path)) {
- filesToScan.add(path.toString());
- } else {
- throw new InternalError("Expecting a .class, .jar or directory: " + path);
- }
- }
- }
- }
-
- private boolean entryIsClassFile(String entry) {
- return entry.endsWith(".class") && !entry.endsWith("module-info.class");
- }
-
- private Set> scanFiles(List filesToScan) {
- Set> classes = new HashSet<>();
- for (String fileName : filesToScan) {
- Set> loaded = scanFile(fileName);
- log.printlnInfo(" " + loaded.size() + " classes loaded.");
- classes.addAll(loaded);
- }
- return classes;
- }
-
- interface ClassLoaderFactory {
- ClassLoader create() throws IOException;
- }
-
- private Set> loadWithClassLoader(ClassLoaderFactory factory, Path root, FileSystemFinder finder) {
- ClassLoader loader = null;
- try {
- loader = factory.create();
- return loadClassFiles(root, finder, loader);
- } catch (IOException e) {
- throw new InternalError(e);
- } finally {
- if (loader instanceof AutoCloseable) {
- try {
- ((AutoCloseable) loader).close();
- } catch (Exception e) {
- throw new InternalError(e);
- }
- }
- }
- }
-
- private Set> scanFile(String fileName) {
- log.printInfo("Scanning: " + fileName + " ...");
- log.printlnVerbose(" "); // Break line
-
- if (fileName.endsWith(".jar")) {
- return loadFromJarFile(fileName);
- } else if (fileName.endsWith(".class")) {
- Set> classes = new HashSet<>();
- loadFromClassFile(fileName, classes);
- return classes;
- } else {
- return scanClassPath(fileName);
- }
- }
-
- private Set> loadFromJarFile(String fileName) {
- FileSystem fs = makeFileSystem(fileName);
- FileSystemFinder finder = new FileSystemFinder(fs.getPath("/"), pathname -> entryIsClassFile(pathname.toString()));
- return loadWithClassLoader(() -> URLClassLoader.newInstance(buildUrls(fileName)), fs.getPath("/"), finder);
- }
-
- private void loadFromClassFile(String fileName, Set> classes) {
- Class> result;
- File file = new File(options.classpath);
- try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) {
- result = loadClassFile(loader, fileName);
- } catch (IOException e) {
- throw new InternalError(e);
- }
- Class> c = result;
- addClass(classes, fileName, c);
- }
-
- private Set> scanClassPath(String fileName) {
- Path classPath = Paths.get(options.classpath);
- if (!Files.exists(classPath)) {
- throw new InternalError("Path does not exist: " + classPath);
- }
- if (!Files.isDirectory(classPath)) {
- throw new InternalError("Path must be a directory: " + classPath);
- }
-
- // Combine class path and file name and see what it is.
- Path combinedPath = Paths.get(options.classpath + File.separator + fileName);
- if (combinedPath.endsWith(".class")) {
- throw new InternalError("unimplemented");
- } else if (Files.isDirectory(combinedPath)) {
- return scanDirectory(classPath, combinedPath);
- } else {
- throw new InternalError("Expecting a .class, .jar or directory: " + fileName);
- }
- }
-
- private FileSystem makeFileSystem(String fileName) {
- try {
- return FileSystems.newFileSystem(makeJarFileURI(fileName), new HashMap<>());
- } catch (IOException e) {
- throw new InternalError(e);
- }
- }
-
- private URI makeJarFileURI(String fileName) {
- try {
- return new URI("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/");
- } catch (URISyntaxException e) {
- throw new InternalError(e);
- }
- }
-
- private PathMatcher combine(PathMatcher m1, PathMatcher m2) {
- return path -> m1.matches(path) && m2.matches(path);
- }
-
- private Set> scanDirectory(Path classPath, Path combinedPath) {
- String dir = options.classpath;
-
- FileSystem fileSystem = FileSystems.getDefault();
- PathMatcher matcher = fileSystem.getPathMatcher("glob:" + "*.class");
- FileSystemFinder finder = new FileSystemFinder(combinedPath,
- combine(matcher, pathname -> entryIsClassFile(pathname.toString())));
-
- File file = new File(dir);
- try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) {
- return loadClassFiles(classPath, finder, loader);
- } catch (IOException e) {
- throw new InternalError(e);
- }
- }
-
- private Set> loadClassFiles(Path root, FileSystemFinder finder, ClassLoader loader) {
- Set> classes = new HashSet<>();
- for (Path name : finder.done()) {
- // Now relativize to the class path so we get the actual class names.
- String entry = root.relativize(name).normalize().toString();
- Class> c = loadClassFile(loader, entry);
- addClass(classes, entry, c);
- }
- return classes;
- }
-
- private void addClass(Set> classes, String name, Class> c) {
- if (c != null) {
- classes.add(c);
- log.printlnVerbose(" loaded " + name);
- }
- }
-
- private URL[] buildUrls(String fileName) throws MalformedURLException {
- return new URL[]{ new URL("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/") };
- }
-
- private URL[] buildUrls(File file) throws MalformedURLException {
- return new URL[] {file.toURI().toURL() };
- }
-
- private Path getModuleDirectory(String modulepath, String module) {
- FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
- return fs.getPath(modulepath, module);
- }
-
- /**
- * Loads a class with the given file name from the specified {@link URLClassLoader}.
- */
- private Class> loadClassFile(final ClassLoader loader, final String fileName) {
- int start = 0;
- if (fileName.startsWith("/")) {
- start = 1;
- }
- String className = fileName.substring(start, fileName.length() - ".class".length());
- className = className.replace('/', '.');
- try {
- return loader.loadClass(className);
- } catch (Throwable e) {
- // If we are running in JCK mode we ignore all exceptions.
- if (options.ignoreClassLoadingErrors) {
- log.printError(className + ": " + e);
- return null;
- }
- throw new InternalError(e);
- }
- }
-
- /**
- * {@link FileVisitor} implementation to find class files recursively.
- */
- private static class FileSystemFinder extends SimpleFileVisitor {
- private final ArrayList fileNames = new ArrayList<>();
- private final PathMatcher filter;
-
- FileSystemFinder(Path combinedPath, PathMatcher filter) {
- this.filter = filter;
- try {
- Files.walkFileTree(combinedPath, this);
- } catch (IOException e) {
- throw new InternalError(e);
- }
- }
-
- /**
- * Compares the glob pattern against the file name.
- */
- void find(Path file) {
- Path name = file.getFileName();
- if (name != null && filter.matches(name)) {
- fileNames.add(file);
- }
- }
-
- List done() {
- return fileNames;
- }
-
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
- find(file);
- return CONTINUE;
- }
-
- @Override
- public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
- find(dir);
- return CONTINUE;
- }
-
- }
-}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java
new file mode 100644
index 00000000000..3fd63b2c0b8
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect;
+
+import jdk.tools.jaotc.LoadedClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassSearch {
+ private List providers = new ArrayList<>();
+
+ public void addProvider(SourceProvider provider) {
+ providers.add(provider);
+ }
+
+ public List search(List search, SearchPath searchPath) {
+ List loaded = new ArrayList<>();
+
+ List sources = new ArrayList<>();
+
+ for (SearchFor entry : search) {
+ sources.add(findSource(entry, searchPath));
+ }
+
+ for (ClassSource source : sources) {
+ source.eachClass((name, loader) -> loaded.add(loadClass(name, loader)));
+ }
+
+ return loaded;
+ }
+
+ private LoadedClass loadClass(String name, ClassLoader loader) {
+ try {
+ Class> clzz = loader.loadClass(name);
+ return new LoadedClass(name, clzz);
+ } catch (ClassNotFoundException e) {
+ throw new InternalError("Failed to load with: " + loader, e);
+ }
+ }
+
+ private ClassSource findSource(SearchFor searchFor, SearchPath searchPath) {
+ ClassSource found = null;
+
+ for (SourceProvider provider : providers) {
+ if (!searchFor.isUnknown() && !provider.supports(searchFor.getType())) {
+ continue;
+ }
+
+ ClassSource source = provider.findSource(searchFor.getName(), searchPath);
+ if (source != null) {
+ if (found != null) {
+ throw new InternalError("Multiple possible sources: " + source + " and: " + found);
+ }
+ found = source;
+ }
+ }
+
+ if (found == null) {
+ throw new InternalError("Failed to find: " + searchFor.toString());
+ }
+ return found;
+ }
+
+ public static List makeList(String type, String argument) {
+ List list = new ArrayList<>();
+ String[] elements = argument.split(":");
+ for (String element : elements) {
+ list.add(new SearchFor(element, type));
+ }
+ return list;
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java
new file mode 100644
index 00000000000..8d9b8439760
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public interface ClassSource {
+ static boolean pathIsClassFile(Path entry) {
+ String fileName = entry.getFileName().toString();
+ return fileName.endsWith(".class") && !fileName.endsWith("module-info.class");
+ }
+
+ static String makeClassName(Path path) {
+ String fileName = path.toString();
+
+ if (!fileName.endsWith(".class")) {
+ throw new IllegalArgumentException("File doesn't end with .class: '" + fileName + "'");
+ }
+
+ int start = 0;
+ if (fileName.startsWith("/")) {
+ start = 1;
+ }
+
+ String className = fileName.substring(start, fileName.length() - ".class".length());
+ className = className.replace('/', '.');
+ return className;
+ }
+
+ void eachClass(BiConsumer consumer);
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java
new file mode 100644
index 00000000000..0761c0ae8e1
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.file.*;
+import java.util.HashMap;
+
+public class FileSupport {
+ public boolean exists(Path path) {
+ return Files.exists(path);
+ }
+
+ public boolean isDirectory(Path path) {
+ return Files.isDirectory(path);
+ }
+
+ private FileSystem makeJarFileSystem(Path path) {
+ try {
+ return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>());
+ } catch (IOException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ private URI makeJarFileURI(Path path) {
+ try {
+ return new URI("jar:file:" + path.toAbsolutePath() + "!/");
+ } catch (URISyntaxException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ public ClassLoader createClassLoader(Path path, ClassLoader parent) {
+ try {
+ return URLClassLoader.newInstance(buildUrls(path), parent);
+ } catch (MalformedURLException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ public ClassLoader createClassLoader(Path path) throws MalformedURLException {
+ return URLClassLoader.newInstance(buildUrls(path));
+ }
+
+ private URL[] buildUrls(Path path) throws MalformedURLException {
+ return new URL[] { path.toUri().toURL() };
+ }
+
+ public Path getJarFileSystemRoot(Path jarFile) {
+ FileSystem fileSystem = makeJarFileSystem(jarFile);
+ return fileSystem.getPath("/");
+ }
+
+ public boolean isAbsolute(Path entry) {
+ return entry.isAbsolute();
+ }
+
+ public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException {
+ DirectoryStream paths = fileSystem.provider().newDirectoryStream(root,null);
+ for (Path entry : paths) {
+ Path relative = root.relativize(entry);
+ if (relative.equals(path)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java
new file mode 100644
index 00000000000..7838104b89c
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect;
+
+import java.io.IOException;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+/**
+ * {@link FileVisitor} implementation to find class files recursively.
+ */
+public class FileSystemFinder extends SimpleFileVisitor implements Iterable {
+ private final ArrayList fileNames = new ArrayList<>();
+ private final PathMatcher filter;
+
+ public FileSystemFinder(Path combinedPath, PathMatcher filter) {
+ this.filter = filter;
+ try {
+ Files.walkFileTree(combinedPath, this);
+ } catch (IOException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ /**
+ * Compares the glob pattern against the file name.
+ */
+ private void find(Path file) {
+ Path name = file.getFileName();
+ if (name != null && filter.matches(name)) {
+ fileNames.add(file);
+ }
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ find(file);
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ find(dir);
+ return CONTINUE;
+ }
+
+
+ @Override
+ public Iterator iterator() {
+ return fileNames.iterator();
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java
new file mode 100644
index 00000000000..49e0cdd9945
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect;
+
+public class SearchFor {
+ private final String name;
+ private final String type;
+
+ public SearchFor(String name) {
+ this(name, "unknown");
+ }
+
+ public SearchFor(String name, String type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public boolean isUnknown() {
+ return "unknown".equals(type);
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String toString() {
+ return type + ":" + name;
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java
new file mode 100644
index 00000000000..19442069f16
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect;
+
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SearchPath {
+ private final List searchPaths = new ArrayList<>();
+ private final FileSupport fileSupport;
+
+ public SearchPath() {
+ this(new FileSupport());
+ }
+
+ public SearchPath(FileSupport fileSupport) {
+ this.fileSupport = fileSupport;
+ }
+
+ public Path find(FileSystem fileSystem, Path entry, String... defaults) {
+ if (isAbsolute(entry)) {
+ if (exists(entry)) {
+ return entry;
+ }
+ return null;
+ }
+
+ if (exists(entry)) {
+ return entry;
+ }
+
+ for (String searchPath : defaults) {
+ Path newPath = fileSystem.getPath(searchPath, entry.toString());
+ if (exists(newPath)) {
+ return newPath;
+ }
+ }
+
+ for (Path searchPath : searchPaths) {
+ Path newPath = fileSystem.getPath(searchPath.toString(), entry.toString());
+ if (exists(newPath)) {
+ return newPath;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean isAbsolute(Path entry) {
+ return fileSupport.isAbsolute(entry);
+ }
+
+ private boolean exists(Path entry) {
+ return fileSupport.exists(entry);
+ }
+
+ public void add(String... paths) {
+ for (String name : paths) {
+ Path path = Paths.get(name);
+ searchPaths.add(path);
+ }
+ }
+}
+
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java
new file mode 100644
index 00000000000..5effa83c8fa
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect;
+
+public interface SourceProvider {
+ ClassSource findSource(String name, SearchPath searchPath);
+
+ boolean supports(String type);
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java
new file mode 100644
index 00000000000..22227d03882
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect.classname;
+
+import jdk.tools.jaotc.collect.ClassSource;
+
+import java.util.function.BiConsumer;
+
+public class ClassNameSource implements ClassSource {
+ private final String name;
+ private final ClassLoader classLoader;
+
+ public ClassNameSource(String name, ClassLoader classLoader) {
+ this.name = name;
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public void eachClass(BiConsumer consumer) {
+ consumer.accept(name, classLoader);
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java
new file mode 100644
index 00000000000..b5bc2804ed4
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect.classname;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class ClassNameSourceProvider implements SourceProvider {
+ public final static String TYPE = "classname";
+ private final ClassLoader classLoader;
+
+ public ClassNameSourceProvider(FileSupport fileSupport) {
+ String classPath = System.getProperty("java.class.path");
+ ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+ if (classPath != null && !classPath.isEmpty()) {
+ classLoader = systemClassLoader;
+ } else {
+ Path path = Paths.get(".").toAbsolutePath();
+ classLoader = fileSupport.createClassLoader(path, systemClassLoader);
+ }
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ try {
+ classLoader.loadClass(name);
+ return new ClassNameSource(name, classLoader);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return TYPE.equals(type);
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java
new file mode 100644
index 00000000000..8e5cdb5bc47
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect.directory;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public class DirectorySource implements ClassSource {
+ private final Path directoryPath;
+ private final ClassLoader classLoader;
+
+ public DirectorySource(Path directoryPath, ClassLoader classLoader) {
+ this.directoryPath = directoryPath;
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public void eachClass(BiConsumer consumer) {
+ FileSystemFinder finder = new FileSystemFinder(directoryPath, ClassSource::pathIsClassFile);
+
+ for (Path path : finder) {
+ consumer.accept(ClassSource.makeClassName(directoryPath.relativize(path).normalize()), classLoader);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "directory:" + directoryPath.toString();
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java
new file mode 100644
index 00000000000..013e3858830
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect.directory;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.net.MalformedURLException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+public class DirectorySourceProvider implements SourceProvider {
+ private final FileSupport fileSupport;
+ private final FileSystem fileSystem;
+ public final static String TYPE = "directory";
+
+ public DirectorySourceProvider(FileSupport fileSupport) {
+ this.fileSupport = fileSupport;
+ fileSystem = FileSystems.getDefault();
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ Path directoryPath = fileSystem.getPath(name);
+
+ if (!fileSupport.exists(directoryPath)) {
+ return null;
+ }
+ if (!fileSupport.isDirectory(directoryPath)) {
+ return null;
+ }
+
+ try {
+ ClassLoader classLoader = fileSupport.createClassLoader(directoryPath);
+ return new DirectorySource(directoryPath, classLoader);
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return TYPE.equals(type);
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java
new file mode 100644
index 00000000000..af7330a53b8
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect.jar;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public class JarFileSource implements ClassSource {
+ private final Path jarFile;
+ private final Path jarRootPath;
+ private final ClassLoader classLoader;
+
+
+ public JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) {
+ this.jarFile = jarFile;
+ this.jarRootPath = jarRootPath;
+ this.classLoader = classLoader;
+ }
+
+ public void eachClass(BiConsumer consumer) {
+ FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile);
+
+ for (Path path : finder) {
+ consumer.accept(ClassSource.makeClassName(jarRootPath.relativize(path).normalize()), classLoader);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "jar:" + jarFile.toString();
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java
new file mode 100644
index 00000000000..f876c740b74
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect.jar;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.net.MalformedURLException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.ProviderNotFoundException;
+
+public class JarSourceProvider implements SourceProvider {
+ private final FileSystem fileSystem;
+ private final FileSupport fileSupport;
+ public final static String TYPE = "jar";
+
+ public JarSourceProvider() {
+ this(new FileSupport());
+ }
+
+ public JarSourceProvider(FileSupport fileSupport) {
+ this.fileSupport = fileSupport;
+ fileSystem = FileSystems.getDefault();
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ Path fileName = fileSystem.getPath(name);
+ Path jarFile = searchPath.find(fileSystem, fileName);
+
+ if (!validPath(jarFile)) {
+ return null;
+ }
+
+ return createSource(jarFile);
+ }
+
+ private ClassSource createSource(Path jarFile) {
+ try {
+ Path jarRootPath = fileSupport.getJarFileSystemRoot(jarFile);
+ if (jarRootPath == null) {
+ return null;
+ }
+ ClassLoader classLoader = fileSupport.createClassLoader(jarFile);
+ return new JarFileSource(jarFile, jarRootPath, classLoader);
+ } catch (ProviderNotFoundException | MalformedURLException e) {
+ }
+ return null;
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return TYPE.equals(type);
+ }
+
+ private boolean validPath(Path jarFile) {
+ return jarFile != null && !fileSupport.isDirectory(jarFile);
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java
new file mode 100644
index 00000000000..bac5624ab6a
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect.module;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSystemFinder;
+
+import java.nio.file.Path;
+import java.util.function.BiConsumer;
+
+public class ModuleSource implements ClassSource {
+ private final Path modulePath;
+ private final ClassLoader classLoader;
+
+ public ModuleSource(Path modulePath, ClassLoader classLoader) {
+ this.modulePath = modulePath;
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public void eachClass(BiConsumer consumer) {
+ FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile);
+
+ for (Path path : finder) {
+ consumer.accept(ClassSource.makeClassName(modulePath.relativize(path).normalize()), classLoader);
+ }
+ }
+
+ public Path getModulePath() {
+ return modulePath;
+ }
+
+ @Override
+ public String toString() {
+ return "module:" + modulePath.toString();
+ }
+}
diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java
new file mode 100644
index 00000000000..cd1a464b6f9
--- /dev/null
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jaotc.collect.module;
+
+import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.SearchPath;
+import jdk.tools.jaotc.collect.SourceProvider;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+public class ModuleSourceProvider implements SourceProvider {
+ private final FileSystem fileSystem;
+ private final ClassLoader classLoader;
+ private final FileSupport fileSupport;
+ public final static String TYPE = "module";
+
+ public ModuleSourceProvider() {
+ this(FileSystems.getFileSystem(URI.create("jrt:/")), ClassLoader.getSystemClassLoader(), new FileSupport());
+ }
+
+ public ModuleSourceProvider(FileSystem fileSystem, ClassLoader classLoader, FileSupport fileSupport) {
+ this.fileSystem = fileSystem;
+ this.classLoader = classLoader;
+ this.fileSupport = fileSupport;
+ }
+
+ @Override
+ public ClassSource findSource(String name, SearchPath searchPath) {
+ Path path = fileSystem.getPath(name);
+ Path dir = fileSystem.getPath("modules");
+
+ if (dir == null || !fileSupport.isDirectory(dir)) {
+ return null;
+ }
+
+ Path found = findModuleDirectory(dir, path);
+
+ if (found == null) {
+ return null;
+ }
+
+ return new ModuleSource(found, classLoader);
+ }
+
+ private Path findModuleDirectory(Path root, Path path) {
+ try {
+ return fileSupport.getSubDirectory(fileSystem, root, path);
+ } catch (IOException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ @Override
+ public boolean supports(String type) {
+ return TYPE.equals(type);
+ }
+}
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java
index f92f91b7c78..e0b5acb426f 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java
@@ -100,15 +100,19 @@ final class CompilerToVM {
native long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method);
/**
- * Determines if {@code method} can be inlined. A method may not be inlinable for a number of
- * reasons such as:
- *
- *
a CompileOracle directive may prevent inlining or compilation of methods
- *
the method may have a bytecode breakpoint set
- *
the method may have other bytecode features that require special handling by the VM
- *
+ * Determines whether {@code method} is currently compilable by the JVMCI compiler being used by
+ * the VM. This can return false if JVMCI compilation failed earlier for {@code method}, a
+ * breakpoint is currently set in {@code method} or {@code method} contains other bytecode
+ * features that require special handling by the VM.
*/
- native boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method);
+ native boolean isCompilable(HotSpotResolvedJavaMethodImpl method);
+
+ /**
+ * Determines if {@code method} is targeted by a VM directive (e.g.,
+ * {@code -XX:CompileCommand=dontinline,}) or annotation (e.g.,
+ * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined.
+ */
+ native boolean hasNeverInlineDirective(HotSpotResolvedJavaMethodImpl method);
/**
* Determines if {@code method} should be inlined at any cost. This could be because:
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java
index dc56435038a..af75f81a2ff 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java
@@ -49,13 +49,6 @@ public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod {
*/
boolean isForceInline();
- /**
- * Returns true if this method has a {@code DontInline} annotation.
- *
- * @return true if DontInline annotation present, false otherwise
- */
- boolean isDontInline();
-
/**
* Returns true if this method has a {@code ReservedStackAccess} annotation.
*
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
index ad4c67d0275..393b740a71e 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
@@ -298,15 +298,6 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
return (getFlags() & config().methodFlagsForceInline) != 0;
}
- /**
- * Returns true if this method has a {@code DontInline} annotation.
- *
- * @return true if DontInline annotation present, false otherwise
- */
- public boolean isDontInline() {
- return (getFlags() & config().methodFlagsDontInline) != 0;
- }
-
/**
* Returns true if this method has a {@code ReservedStackAccess} annotation.
*
@@ -582,10 +573,15 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
@Override
public boolean canBeInlined() {
- if (isDontInline()) {
+ if (hasNeverInlineDirective()) {
return false;
}
- return compilerToVM().canInlineMethod(this);
+ return compilerToVM().isCompilable(this);
+ }
+
+ @Override
+ public boolean hasNeverInlineDirective() {
+ return compilerToVM().hasNeverInlineDirective(this);
}
@Override
diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java
index 6d13d911398..dee43ffbc6a 100644
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java
@@ -346,6 +346,13 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
*/
boolean canBeInlined();
+ /**
+ * Determines if this method is targeted by a VM directive (e.g.,
+ * {@code -XX:CompileCommand=dontinline,}) or VM recognized annotation (e.g.,
+ * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined.
+ */
+ boolean hasNeverInlineDirective();
+
/**
* Returns {@code true} if the inlining of this method should be forced.
*/
diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py b/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py
index 402eae2dae5..dda989acedf 100644
--- a/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py
+++ b/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py
@@ -638,6 +638,7 @@ suite = {
"annotationProcessors" : [
"GRAAL_NODEINFO_PROCESSOR",
"GRAAL_REPLACEMENTS_VERIFIER",
+ "GRAAL_OPTIONS_PROCESSOR",
],
"workingSets" : "Graal,Graph",
},
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java
index f5a3758f066..cd5e7fca7ae 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java
@@ -116,6 +116,7 @@ public class Debug {
public static final int INFO_LOG_LEVEL = 2;
public static final int VERBOSE_LOG_LEVEL = 3;
public static final int DETAILED_LOG_LEVEL = 4;
+ public static final int VERY_DETAILED_LOG_LEVEL = 5;
public static boolean isDumpEnabled(int dumpLevel) {
return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel);
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java
index 4ccc1bbc9ef..7cb4b03b27e 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java
@@ -267,10 +267,15 @@ public class AMD64HotSpotBackend extends HotSpotHostBackend {
if (config.useCompressedClassPointers) {
Register register = r10;
- AMD64HotSpotMove.decodeKlassPointer(asm, register, providers.getRegisters().getHeapBaseRegister(), src, config.getKlassEncoding());
- if (config.narrowKlassBase != 0) {
- // The heap base register was destroyed above, so restore it
- asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase);
+ AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, providers.getRegisters().getHeapBaseRegister(), src, config);
+ if (GeneratePIC.getValue()) {
+ asm.movq(providers.getRegisters().getHeapBaseRegister(), asm.getPlaceholder(-1));
+ crb.recordMark(config.MARKID_NARROW_OOP_BASE_ADDRESS);
+ } else {
+ if (config.narrowKlassBase != 0) {
+ // The heap base register was destroyed above, so restore it
+ asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase);
+ }
}
asm.cmpq(inlineCacheKlass, register);
} else {
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java
index f7a5f205c26..168282ebcbf 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java
@@ -265,14 +265,21 @@ public class AMD64HotSpotMove {
}
}
- public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) {
+ public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) {
+ CompressEncoding encoding = config.getKlassEncoding();
masm.movl(register, address);
if (encoding.shift != 0) {
assert encoding.alignment == encoding.shift : "Decode algorithm is wrong";
masm.shlq(register, encoding.alignment);
}
- if (encoding.base != 0) {
- masm.movq(scratch, encoding.base);
+ if (GeneratePIC.getValue() || encoding.base != 0) {
+ if (GeneratePIC.getValue()) {
+ masm.movq(scratch, masm.getPlaceholder(-1));
+ crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS);
+ } else {
+ assert encoding.base != 0;
+ masm.movq(scratch, encoding.base);
+ }
masm.addq(register, scratch);
}
}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java
new file mode 100644
index 00000000000..3a93d463936
--- /dev/null
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot;
+
+import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
+
+public class AOTGraalHotSpotVMConfig extends GraalHotSpotVMConfig {
+ private final CompressEncoding aotOopEncoding;
+ private final CompressEncoding aotKlassEncoding;
+
+ public AOTGraalHotSpotVMConfig(HotSpotVMConfigStore store) {
+ super(store);
+ // In AOT, force the shift to be always equal to alignment therefore avoiding zero-shift.
+ CompressEncoding vmOopEncoding = super.getOopEncoding();
+ aotOopEncoding = new CompressEncoding(vmOopEncoding.base, vmOopEncoding.alignment, vmOopEncoding.alignment);
+ CompressEncoding vmKlassEncoding = super.getKlassEncoding();
+ aotKlassEncoding = new CompressEncoding(vmKlassEncoding.base, vmKlassEncoding.alignment, vmKlassEncoding.alignment);
+ assert check();
+ }
+
+ @Override
+ public CompressEncoding getOopEncoding() {
+ return aotOopEncoding;
+ }
+
+ @Override
+ public CompressEncoding getKlassEncoding() {
+ return aotKlassEncoding;
+ }
+}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
index e7ce8f68cce..898d688747d 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
@@ -479,7 +479,6 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address");
public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*");
- public final int methodFlagsJfrTowrite = getConstant("Method::_jfr_towrite", Integer.class);
public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class);
public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class);
public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class);
@@ -773,13 +772,14 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
public final int MARKID_HEAP_TOP_ADDRESS = getConstant("CodeInstaller::HEAP_TOP_ADDRESS", Integer.class, 17);
public final int MARKID_HEAP_END_ADDRESS = getConstant("CodeInstaller::HEAP_END_ADDRESS", Integer.class, 18);
public final int MARKID_NARROW_KLASS_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_KLASS_BASE_ADDRESS", Integer.class, 19);
- public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 20);
- public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 21);
- public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 22);
+ public final int MARKID_NARROW_OOP_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_OOP_BASE_ADDRESS", Integer.class, 20);
+ public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 21);
+ public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 22);
+ public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 23);
// Checkstyle: resume
- private boolean check() {
+ protected boolean check() {
for (Field f : getClass().getDeclaredFields()) {
int modifiers = f.getModifiers();
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
index 01401eafd4a..401169124f4 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
@@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.hotspot;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.debug.GraalDebugConfig.areScopedGlobalMetricsEnabled;
import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary;
import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
@@ -99,7 +100,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory) {
HotSpotVMConfigStore store = jvmciRuntime.getConfigStore();
- config = new GraalHotSpotVMConfig(store);
+ config = GeneratePIC.getValue() ? new AOTGraalHotSpotVMConfig(store) : new GraalHotSpotVMConfig(store);
CompileTheWorldOptions.overrideWithNativeOptions(config);
// Only set HotSpotPrintInlining if it still has its default value (false).
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
index 89729e7e3f4..10b2255a3dc 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
@@ -22,7 +22,6 @@
*/
package org.graalvm.compiler.hotspot.meta;
-import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.FieldReadEnabledInImmutableCode;
@@ -112,11 +111,6 @@ public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
return true;
}
}
- if (GeneratePIC.getValue()) {
- if (field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) {
- return tryReadField(b, field, null);
- }
- }
if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) {
return true;
}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
index bba5c70cfe4..7ace642641e 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
@@ -1738,9 +1738,8 @@ public class BytecodeParser implements GraphBuilderContext {
} else {
// Intrinsic was not applied: remove intrinsic guard
// and restore the original receiver node in the arguments array
- for (Node node : graph.getNewNodes(intrinsicGuard.mark)) {
- GraphUtil.killCFG(node);
- }
+ intrinsicGuard.lastInstr.setNext(null);
+ GraphUtil.removeNewNodes(graph, intrinsicGuard.mark);
lastInstr = intrinsicGuard.lastInstr;
args[0] = intrinsicGuard.receiver;
}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java
index f26b3004799..f2f833d2a90 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java
@@ -153,9 +153,7 @@ public class SimplifyingGraphDecoder extends GraphDecoder {
}
for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
- if (!(node instanceof FixedNode) && node.hasNoUsages()) {
- GraphUtil.killCFG(node);
- }
+ GraphUtil.tryKillUnused(node);
}
}
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java
index af89e2711de..61603208b96 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java
@@ -506,7 +506,7 @@ public class StructuredGraph extends Graph implements JavaMethodContext {
for (Node successor : snapshot) {
if (successor != null && successor.isAlive()) {
if (successor != survivingSuccessor) {
- GraphUtil.killCFG(successor, tool);
+ GraphUtil.killCFG((FixedNode) successor, tool);
}
}
}
@@ -566,6 +566,9 @@ public class StructuredGraph extends Graph implements JavaMethodContext {
reduceTrivialMerge(begin);
} else { // convert to merge
AbstractMergeNode merge = this.add(new MergeNode());
+ for (EndNode end : begin.forwardEnds()) {
+ merge.addForwardEnd(end);
+ }
this.replaceFixedWithFixed(begin, merge);
}
}
@@ -576,7 +579,14 @@ public class StructuredGraph extends Graph implements JavaMethodContext {
for (PhiNode phi : merge.phis().snapshot()) {
assert phi.valueCount() == 1;
ValueNode singleValue = phi.valueAt(0);
- phi.replaceAtUsagesAndDelete(singleValue);
+ if (phi.hasUsages()) {
+ phi.replaceAtUsagesAndDelete(singleValue);
+ } else {
+ phi.safeDelete();
+ if (singleValue != null) {
+ GraphUtil.tryKillUnused(singleValue);
+ }
+ }
}
// remove loop exits
if (merge instanceof LoopBeginNode) {
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java
index f942d8c2358..210c5f793da 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,18 +22,30 @@
*/
package org.graalvm.compiler.nodes.util;
+import static org.graalvm.compiler.graph.Graph.Options.VerifyGraalGraphEdges;
+import static org.graalvm.compiler.nodes.util.GraphUtil.Options.VerifyKillCFGUnusedNodes;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
+import java.util.Set;
import org.graalvm.compiler.bytecode.Bytecode;
import org.graalvm.compiler.code.SourceStackTraceBailoutException;
+import org.graalvm.compiler.core.common.CollectionsFactory;
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeWorkList;
+import org.graalvm.compiler.graph.Position;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.graph.spi.SimplifierTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractEndNode;
import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -48,11 +60,15 @@ import org.graalvm.compiler.nodes.ProxyNode;
import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
import org.graalvm.compiler.nodes.spi.LimitedValueProxy;
import org.graalvm.compiler.nodes.spi.LoweringProvider;
import org.graalvm.compiler.nodes.spi.ValueProxy;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.options.OptionValue;
import jdk.vm.ci.code.BailoutException;
import jdk.vm.ci.code.BytecodePosition;
@@ -64,22 +80,78 @@ import jdk.vm.ci.meta.ResolvedJavaMethod;
public class GraphUtil {
- public static void killCFG(Node node, SimplifierTool tool) {
- NodeWorkList worklist = killCFG(node, tool, null);
- if (worklist != null) {
- for (Node successor : worklist) {
- killCFG(successor, tool, worklist);
+ public static class Options {
+ @Option(help = "Verify that there are no new unused nodes when performing killCFG", type = OptionType.Debug)//
+ public static final OptionValue VerifyKillCFGUnusedNodes = new OptionValue<>(false);
+ }
+
+ @SuppressWarnings("try")
+ public static void killCFG(FixedNode node, SimplifierTool tool) {
+ try (Debug.Scope scope = Debug.scope("KillCFG", node)) {
+ Set unusedNodes = null;
+ Set unsafeNodes = null;
+ Graph.NodeEventScope nodeEventScope = null;
+ if (VerifyGraalGraphEdges.getValue()) {
+ unsafeNodes = collectUnsafeNodes(node.graph());
+ }
+ if (VerifyKillCFGUnusedNodes.getValue()) {
+ Set collectedUnusedNodes = unusedNodes = CollectionsFactory.newSet();
+ nodeEventScope = node.graph().trackNodeEvents(new Graph.NodeEventListener() {
+ @Override
+ public void event(Graph.NodeEvent e, Node n) {
+ if (e == Graph.NodeEvent.ZERO_USAGES && isFloatingNode(n)) {
+ collectedUnusedNodes.add(n);
+ }
+ }
+ });
+ }
+ Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "Before killCFG %s", node);
+ NodeWorkList worklist = killCFG(node, tool, null);
+ if (worklist != null) {
+ for (Node n : worklist) {
+ killCFG(n, tool, worklist);
+ }
+ }
+ if (VerifyGraalGraphEdges.getValue()) {
+ Set newUnsafeNodes = collectUnsafeNodes(node.graph());
+ newUnsafeNodes.removeAll(unsafeNodes);
+ assert newUnsafeNodes.isEmpty() : "New unsafe nodes: " + newUnsafeNodes;
+ }
+ if (VerifyKillCFGUnusedNodes.getValue()) {
+ nodeEventScope.close();
+ unusedNodes.removeIf(n -> n.isDeleted());
+ assert unusedNodes.isEmpty() : "New unused nodes: " + unusedNodes;
+ }
+ } catch (Throwable t) {
+ throw Debug.handle(t);
+ }
+ }
+
+ /**
+ * Collects all node in the graph which have non-optional inputs that are null.
+ */
+ private static Set collectUnsafeNodes(Graph graph) {
+ Set unsafeNodes = CollectionsFactory.newSet();
+ for (Node n : graph.getNodes()) {
+ for (Position pos : n.inputPositions()) {
+ Node input = pos.get(n);
+ if (input == null) {
+ if (!pos.isInputOptional()) {
+ unsafeNodes.add(n);
+ }
+ }
}
}
+ return unsafeNodes;
}
private static NodeWorkList killCFG(Node node, SimplifierTool tool, NodeWorkList worklist) {
NodeWorkList newWorklist = worklist;
- // DebugScope.forceDump(node.graph(), "kill CFG %s", node);
if (node instanceof FixedNode) {
newWorklist = killCFGLinear((FixedNode) node, newWorklist, tool);
} else {
- propagateKill(node);
+ newWorklist = propagateKill(node, newWorklist);
+ Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "killCFG (Floating) %s", node);
}
return newWorklist;
}
@@ -93,19 +165,20 @@ public class GraphUtil {
if (current instanceof AbstractEndNode) {
// We reached a control flow end.
AbstractEndNode end = (AbstractEndNode) current;
- killEnd(end, tool);
+ newWorklist = killEnd(end, newWorklist, tool);
} else if (current instanceof FixedWithNextNode) {
- next = ((FixedWithNextNode) current).next();
+ // Node guaranteed to have a single successor
+ FixedWithNextNode fixedWithNext = (FixedWithNextNode) current;
+ assert fixedWithNext.successors().count() == 1 || fixedWithNext.successors().count() == 0;
+ assert fixedWithNext.successors().first() == fixedWithNext.next();
+ next = fixedWithNext.next();
} else {
- // Normal control flow node.
/*
* We do not take a successor snapshot because this iterator supports concurrent
* modifications as long as they do not change the size of the successor list. Not
* taking a snapshot allows us to see modifications to other branches that may
* happen while processing one branch.
*/
- // assert node.successors().count() > 1 || node.successors().count() == 0 :
- // node.getClass();
Iterator successors = current.successors().iterator();
if (successors.hasNext()) {
Node first = successors.next();
@@ -126,100 +199,158 @@ public class GraphUtil {
}
}
current.replaceAtPredecessor(null);
- propagateKill(current);
+ newWorklist = propagateKill(current, newWorklist);
+ Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, current.graph(), "killCFGLinear %s", current);
current = next;
}
+ Debug.dump(Debug.DETAILED_LOG_LEVEL, in.graph(), "killCFGLinear %s", in);
return newWorklist;
}
- public static void killCFG(Node node) {
+ public static void killCFG(FixedNode node) {
killCFG(node, null);
}
- private static void killEnd(AbstractEndNode end, SimplifierTool tool) {
+ /**
+ * Node type used temporarily while deleting loops.
+ *
+ * It is used as replacement for the loop {@link PhiNode PhiNodes} in order to break data-flow
+ * cycles before deleting the loop. The control-flow of the whole loop is killed before killing
+ * the poison node if they are still alive.
+ */
+ @NodeInfo(allowedUsageTypes = InputType.Unchecked)
+ private static final class PoisonNode extends FloatingNode {
+ public static final NodeClass TYPE = NodeClass.create(PoisonNode.class);
+
+ protected PoisonNode() {
+ super(TYPE, StampFactory.forVoid());
+ }
+ }
+
+ private static NodeWorkList killEnd(AbstractEndNode end, NodeWorkList worklist, SimplifierTool tool) {
+ NodeWorkList newWorklist = worklist;
AbstractMergeNode merge = end.merge();
if (merge != null) {
merge.removeEnd(end);
StructuredGraph graph = end.graph();
if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) {
// dead loop
- for (PhiNode phi : merge.phis().snapshot()) {
- propagateKill(phi);
- }
LoopBeginNode begin = (LoopBeginNode) merge;
// disconnect and delete loop ends & loop exits
for (LoopEndNode loopend : begin.loopEnds().snapshot()) {
loopend.predecessor().replaceFirstSuccessor(loopend, null);
loopend.safeDelete();
}
- begin.removeExits();
- FixedNode loopBody = begin.next();
- if (loopBody != null) { // for small infinite loops, the body may be killed while
- // killing the loop ends
- killCFG(loopBody);
+ // clean unused proxies to avoid creating new unused nodes
+ for (LoopExitNode exit : begin.loopExits()) {
+ for (ProxyNode vpn : exit.proxies().snapshot()) {
+ tryKillUnused(vpn);
+ }
}
+ begin.removeExits();
+ PoisonNode poison = null;
+ if (merge.phis().isNotEmpty()) {
+ poison = graph.unique(new PoisonNode());
+ for (PhiNode phi : merge.phis()) {
+ phi.replaceAtUsages(poison);
+ }
+ for (PhiNode phi : merge.phis().snapshot()) {
+ killWithUnusedFloatingInputs(phi);
+ }
+ }
+ FixedNode loopBody = begin.next();
+ Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, end.graph(), "killEnd (Loop) %s after initial loop cleanup", end);
+ if (loopBody != null) {
+ // for small infinite loops, the body may already be killed while killing the
+ // LoopEnds
+ newWorklist = killCFG(loopBody, tool, worklist);
+ }
+ FrameState frameState = begin.stateAfter();
begin.safeDelete();
+ if (frameState != null) {
+ tryKillUnused(frameState);
+ }
+ if (poison != null && poison.isAlive()) {
+ if (newWorklist == null) {
+ newWorklist = graph.createNodeWorkList();
+ }
+ // drain the worklist to finish the loop before adding the poison
+ for (Node n : newWorklist) {
+ killCFG(n, tool, newWorklist);
+ }
+ if (poison.isAlive()) {
+ newWorklist.add(poison);
+ }
+ }
} else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
// not a loop anymore
if (tool != null) {
- merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
+ for (PhiNode phi : merge.phis()) {
+ tool.addToWorkList(phi.usages());
+ }
}
graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
} else if (merge.phiPredecessorCount() == 1) {
// not a merge anymore
if (tool != null) {
- merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
+ for (PhiNode phi : merge.phis()) {
+ tool.addToWorkList(phi.usages());
+ }
}
graph.reduceTrivialMerge(merge);
}
}
+ return newWorklist;
}
public static boolean isFloatingNode(Node n) {
return !(n instanceof FixedNode);
}
- private static void propagateKill(Node node) {
+ private static NodeWorkList propagateKill(Node node, NodeWorkList workList) {
+ NodeWorkList newWorkList = workList;
if (node != null && node.isAlive()) {
- node.markDeleted();
-
- for (Node in : node.inputs()) {
- if (in.isAlive()) {
- in.removeUsage(node);
- if (in.hasNoUsages() && !(in instanceof FixedNode)) {
- killWithUnusedFloatingInputs(in);
- }
- }
- }
-
- ArrayList usageToKill = null;
- for (Node usage : node.usages()) {
- if (usage.isAlive() && !(usage instanceof FixedNode)) {
- if (usageToKill == null) {
- usageToKill = new ArrayList<>();
- }
- usageToKill.add(usage);
- }
- }
- if (usageToKill != null) {
- for (Node usage : usageToKill) {
- if (usage.isAlive()) {
- if (usage instanceof PhiNode) {
- PhiNode phiNode = (PhiNode) usage;
- usage.replaceFirstInput(node, null);
- if (phiNode.merge() == null || !phiNode.hasValidInput()) {
- propagateKill(usage);
- }
+ for (Node usage : node.usages().snapshot()) {
+ assert usage.isAlive();
+ if (isFloatingNode(usage)) {
+ boolean addUsage = false;
+ if (usage instanceof PhiNode) {
+ PhiNode phi = (PhiNode) usage;
+ assert phi.merge() != null;
+ if (phi.merge() == node) {
+ // we reach the phi directly through he merge, queue it.
+ addUsage = true;
} else {
- propagateKill(usage);
+ // we reach it though a value
+ assert phi.values().contains(node);
+ // let that be handled when we reach the corresponding End node
}
+ } else {
+ addUsage = true;
+ }
+ if (addUsage) {
+ if (newWorkList == null) {
+ newWorkList = node.graph().createNodeWorkList();
+ }
+ newWorkList.add(usage);
}
}
+ usage.replaceFirstInput(node, null);
}
+ killWithUnusedFloatingInputs(node);
}
+ return newWorkList;
+ }
+
+ private static boolean checkKill(Node node) {
+ node.assertTrue(node.isAlive(), "must be alive");
+ node.assertTrue(node.hasNoUsages(), "cannot kill node %s because of usages: %s", node, node.usages());
+ node.assertTrue(node.predecessor() == null, "cannot kill node %s because of predecessor: %s", node, node.predecessor());
+ return true;
}
public static void killWithUnusedFloatingInputs(Node node) {
+ assert checkKill(node);
node.markDeleted();
outer: for (Node in : node.inputs()) {
if (in.isAlive()) {
@@ -227,7 +358,7 @@ public class GraphUtil {
if (in.hasNoUsages()) {
node.maybeNotifyZeroUsages(in);
}
- if (!(in instanceof FixedNode)) {
+ if (isFloatingNode(in)) {
if (in.hasNoUsages()) {
killWithUnusedFloatingInputs(in);
} else if (in instanceof PhiNode) {
@@ -244,6 +375,35 @@ public class GraphUtil {
}
}
+ /**
+ * Removes all nodes created after the {@code mark}, assuming no "old" nodes point to "new"
+ * nodes.
+ */
+ public static void removeNewNodes(Graph graph, Graph.Mark mark) {
+ assert checkNoOldToNewEdges(graph, mark);
+ for (Node n : graph.getNewNodes(mark)) {
+ n.markDeleted();
+ for (Node in : n.inputs()) {
+ in.removeUsage(n);
+ }
+ }
+ }
+
+ private static boolean checkNoOldToNewEdges(Graph graph, Graph.Mark mark) {
+ for (Node old : graph.getNodes()) {
+ if (graph.isNew(mark, old)) {
+ break;
+ }
+ for (Node n : old.successors()) {
+ assert !graph.isNew(mark, n) : old + " -> " + n;
+ }
+ for (Node n : old.inputs()) {
+ assert !graph.isNew(mark, n) : old + " -> " + n;
+ }
+ }
+ return true;
+ }
+
public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) {
if (fixed instanceof StateSplit) {
FrameState stateAfter = ((StateSplit) fixed).stateAfter();
@@ -688,8 +848,9 @@ public class GraphUtil {
@Override
public void deleteBranch(Node branch) {
- branch.predecessor().replaceFirstSuccessor(branch, null);
- GraphUtil.killCFG(branch, this);
+ FixedNode fixedBranch = (FixedNode) branch;
+ fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null);
+ GraphUtil.killCFG(fixedBranch, this);
}
@Override
diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java
index 35c0a41a7fb..d57d0d45c7a 100644
--- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java
+++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java
@@ -444,8 +444,9 @@ public class CanonicalizerPhase extends BasePhase {
@Override
public void deleteBranch(Node branch) {
- branch.predecessor().replaceFirstSuccessor(branch, null);
- GraphUtil.killCFG(branch, this);
+ FixedNode fixedBranch = (FixedNode) branch;
+ fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null);
+ GraphUtil.killCFG(fixedBranch, this);
}
@Override
diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp
index e900ce0af77..014d306e37f 100644
--- a/hotspot/src/os/aix/vm/os_aix.cpp
+++ b/hotspot/src/os/aix/vm/os_aix.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 SAP SE. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -632,7 +632,6 @@ void os::Aix::signal_sets_init() {
sigaddset(&unblocked_sigs, SIGBUS);
sigaddset(&unblocked_sigs, SIGFPE);
sigaddset(&unblocked_sigs, SIGTRAP);
- sigaddset(&unblocked_sigs, SIGDANGER);
sigaddset(&unblocked_sigs, SR_signum);
if (!ReduceSignalUsage) {
@@ -1553,6 +1552,8 @@ void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) {
print_signal_handler(st, SHUTDOWN3_SIGNAL , buf, buflen);
print_signal_handler(st, BREAK_SIGNAL, buf, buflen);
print_signal_handler(st, SIGTRAP, buf, buflen);
+ // We also want to know if someone else adds a SIGDANGER handler because
+ // that will interfere with OOM killling.
print_signal_handler(st, SIGDANGER, buf, buflen);
}
@@ -3156,7 +3157,6 @@ void os::Aix::install_signal_handlers() {
set_signal_handler(SIGFPE, true);
set_signal_handler(SIGTRAP, true);
set_signal_handler(SIGXFSZ, true);
- set_signal_handler(SIGDANGER, true);
if (libjsig_is_loaded) {
// Tell libjsig jvm finishes setting signal handlers.
@@ -3273,7 +3273,6 @@ void os::run_periodic_checks() {
if (UseSIGTRAP) {
DO_SIGNAL_CHECK(SIGTRAP);
}
- DO_SIGNAL_CHECK(SIGDANGER);
// ReduceSignalUsage allows the user to override these handlers
// see comments at the very top and jvm_solaris.h
diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp
index 5142cd37a25..23ad8e209cb 100644
--- a/hotspot/src/os/windows/vm/os_windows.cpp
+++ b/hotspot/src/os/windows/vm/os_windows.cpp
@@ -778,6 +778,11 @@ void os::set_native_thread_name(const char *name) {
// is already attached to a debugger; debugger must observe
// the exception below to show the correct name.
+ // If there is no debugger attached skip raising the exception
+ if (!IsDebuggerPresent()) {
+ return;
+ }
+
const DWORD MS_VC_EXCEPTION = 0x406D1388;
struct {
DWORD dwType; // must be 0x1000
diff --git a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp
index 9bbb9387c54..721d99668b4 100644
--- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp
+++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 SAP SE. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -258,13 +258,6 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
}
}
- // Handle SIGDANGER right away. AIX would raise SIGDANGER whenever available swap
- // space falls below 30%. This is only a chance for the process to gracefully abort.
- // We can't hope to proceed after SIGDANGER since SIGKILL tailgates.
- if (sig == SIGDANGER) {
- goto report_and_die;
- }
-
if (info == NULL || uc == NULL || thread == NULL && vmthread == NULL) {
goto run_chained_handler;
}
diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp
index 24c124a4e8d..7767cecf0e4 100644
--- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp
@@ -87,6 +87,7 @@
#define SPELL_REG_FP "rbp"
#else
#define REG_FP 29
+#define REG_LR 30
#define SPELL_REG_SP "sp"
#define SPELL_REG_FP "x29"
@@ -182,6 +183,46 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
return frame(sp, fp, epc.pc());
}
+bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
+ address pc = (address) os::Linux::ucontext_get_pc(uc);
+ if (Interpreter::contains(pc)) {
+ // interpreter performs stack banging after the fixed frame header has
+ // been generated while the compilers perform it before. To maintain
+ // semantic consistency between interpreted and compiled frames, the
+ // method returns the Java sender of the current frame.
+ *fr = os::fetch_frame_from_context(uc);
+ if (!fr->is_first_java_frame()) {
+ assert(fr->safe_for_sender(thread), "Safety check");
+ *fr = fr->java_sender();
+ }
+ } else {
+ // more complex code with compiled code
+ assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
+ CodeBlob* cb = CodeCache::find_blob(pc);
+ if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
+ // Not sure where the pc points to, fallback to default
+ // stack overflow handling
+ return false;
+ } else {
+ // In compiled code, the stack banging is performed before LR
+ // has been saved in the frame. LR is live, and SP and FP
+ // belong to the caller.
+ intptr_t* fp = os::Linux::ucontext_get_fp(uc);
+ intptr_t* sp = os::Linux::ucontext_get_sp(uc);
+ address pc = (address)(uc->uc_mcontext.regs[REG_LR]
+ - NativeInstruction::instruction_size);
+ *fr = frame(sp, fp, pc);
+ if (!fr->is_java_frame()) {
+ assert(fr->safe_for_sender(thread), "Safety check");
+ assert(!fr->is_first_frame(), "Safety check");
+ *fr = fr->java_sender();
+ }
+ }
+ }
+ assert(fr->is_java_frame(), "Safety check");
+ return true;
+}
+
// By default, gcc always saves frame pointer rfp on this stack. This
// may get turned off by -fomit-frame-pointer.
frame os::get_sender_for_C_frame(frame* fr) {
@@ -313,6 +354,24 @@ JVM_handle_linux_signal(int sig,
if (thread->in_stack_yellow_reserved_zone(addr)) {
thread->disable_stack_yellow_reserved_zone();
if (thread->thread_state() == _thread_in_Java) {
+ if (thread->in_stack_reserved_zone(addr)) {
+ frame fr;
+ if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
+ assert(fr.is_java_frame(), "Must be a Java frame");
+ frame activation =
+ SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
+ if (activation.sp() != NULL) {
+ thread->disable_stack_reserved_zone();
+ if (activation.is_interpreted_frame()) {
+ thread->set_reserved_stack_activation((address)(
+ activation.fp() + frame::interpreter_frame_initial_sp_offset));
+ } else {
+ thread->set_reserved_stack_activation((address)activation.unextended_sp());
+ }
+ return 1;
+ }
+ }
+ }
// Throw a stack overflow exception. Guard pages will be reenabled
// while unwinding the stack.
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
diff --git a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp
index 684853cfd34..e9120a8b696 100644
--- a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp
+++ b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp
@@ -144,6 +144,42 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
return frame(sp, epc.pc());
}
+bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
+ address pc = (address) os::Linux::ucontext_get_pc(uc);
+ if (Interpreter::contains(pc)) {
+ // Interpreter performs stack banging after the fixed frame header has
+ // been generated while the compilers perform it before. To maintain
+ // semantic consistency between interpreted and compiled frames, the
+ // method returns the Java sender of the current frame.
+ *fr = os::fetch_frame_from_context(uc);
+ if (!fr->is_first_java_frame()) {
+ assert(fr->safe_for_sender(thread), "Safety check");
+ *fr = fr->java_sender();
+ }
+ } else {
+ // More complex code with compiled code.
+ assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
+ CodeBlob* cb = CodeCache::find_blob(pc);
+ if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
+ // Not sure where the pc points to, fallback to default
+ // stack overflow handling. In compiled code, we bang before
+ // the frame is complete.
+ return false;
+ } else {
+ intptr_t* fp = os::Linux::ucontext_get_fp(uc);
+ intptr_t* sp = os::Linux::ucontext_get_sp(uc);
+ *fr = frame(sp, (address)*sp);
+ if (!fr->is_java_frame()) {
+ assert(fr->safe_for_sender(thread), "Safety check");
+ assert(!fr->is_first_frame(), "Safety check");
+ *fr = fr->java_sender();
+ }
+ }
+ }
+ assert(fr->is_java_frame(), "Safety check");
+ return true;
+}
+
frame os::get_sender_for_C_frame(frame* fr) {
if (*fr->sp() == 0) {
// fr is the last C frame.
@@ -279,13 +315,31 @@ JVM_handle_linux_signal(int sig,
if (thread->on_local_stack(addr)) {
// stack overflow
if (thread->in_stack_yellow_reserved_zone(addr)) {
- thread->disable_stack_yellow_reserved_zone();
if (thread->thread_state() == _thread_in_Java) {
+ if (thread->in_stack_reserved_zone(addr)) {
+ frame fr;
+ if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
+ assert(fr.is_java_frame(), "Must be a Javac frame");
+ frame activation =
+ SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
+ if (activation.sp() != NULL) {
+ thread->disable_stack_reserved_zone();
+ if (activation.is_interpreted_frame()) {
+ thread->set_reserved_stack_activation((address)activation.fp());
+ } else {
+ thread->set_reserved_stack_activation((address)activation.unextended_sp());
+ }
+ return 1;
+ }
+ }
+ }
// Throw a stack overflow exception.
// Guard pages will be reenabled while unwinding the stack.
+ thread->disable_stack_yellow_reserved_zone();
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
} else {
// Thread was in the vm or native code. Return and try to finish.
+ thread->disable_stack_yellow_reserved_zone();
return 1;
}
} else if (thread->in_stack_red_zone(addr)) {
diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
index f5c0ff370a0..5fcd2de83df 100644
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
@@ -89,7 +89,10 @@
// Minimum usable stack sizes required to get to user code. Space for
// HotSpot guard pages is added later.
#ifdef _LP64
-size_t os::Posix::_compiler_thread_min_stack_allowed = 202 * K;
+// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler
+// threads requires a large stack with the Solaris Studio C++ compiler version 5.13
+// and product VM builds (debug builds require significantly less stack space).
+size_t os::Posix::_compiler_thread_min_stack_allowed = 325 * K;
size_t os::Posix::_java_thread_min_stack_allowed = 48 * K;
size_t os::Posix::_vm_internal_thread_min_stack_allowed = 224 * K;
#else
diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp
index d9e8726bb58..3bc1fa6aec8 100644
--- a/hotspot/src/share/vm/adlc/formssel.cpp
+++ b/hotspot/src/share/vm/adlc/formssel.cpp
@@ -650,6 +650,7 @@ bool InstructForm::is_wide_memory_kill(FormDict &globals) const {
if( strcmp(_matrule->_opType,"MemBarReleaseLock") == 0 ) return true;
if( strcmp(_matrule->_opType,"MemBarAcquireLock") == 0 ) return true;
if( strcmp(_matrule->_opType,"MemBarStoreStore") == 0 ) return true;
+ if( strcmp(_matrule->_opType,"MemBarVolatile") == 0 ) return true;
if( strcmp(_matrule->_opType,"StoreFence") == 0 ) return true;
if( strcmp(_matrule->_opType,"LoadFence") == 0 ) return true;
diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp
index 08283a92fbe..52e2c8d55b1 100644
--- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp
@@ -25,6 +25,7 @@
#include "aot/aotCodeHeap.hpp"
#include "aot/aotLoader.hpp"
+#include "classfile/javaAssertions.hpp"
#include "gc/g1/heapRegion.hpp"
#include "gc/shared/gcLocker.hpp"
#include "interpreter/abstractInterpreter.hpp"
@@ -294,6 +295,8 @@ void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data
// When the AOT compiler compiles something big we fail to generate metadata
// in CodeInstaller::gather_metadata. In that case the scopes_pcs_begin == scopes_pcs_end.
// In all successful cases we always have 2 entries of scope pcs.
+ log_info(aot, class, resolve)("Failed to load %s (no metadata available)", mh->name_and_sig_as_C_string());
+ _code_to_aot[code_id]._state = invalid;
return;
}
@@ -536,6 +539,7 @@ void AOTCodeHeap::link_global_lib_symbols() {
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_end_address", address, (heap->supports_inline_contig_alloc() ? heap->end_addr() : NULL));
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_polling_page", address, os::get_polling_page());
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, Universe::narrow_klass_base());
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_oop_base_address", address, Universe::narrow_oop_base());
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc());
link_shared_runtime_symbols();
@@ -706,6 +710,12 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) {
return false;
}
+ if (_lib->config()->_omitAssertions && JavaAssertions::enabled(kh->name()->as_C_string(), kh->class_loader() == NULL)) {
+ log_trace(aot, class, load)("class %s in %s does not have java assertions in compiled code, but assertions are enabled for this execution.", kh->internal_name(), _lib->name());
+ sweep_dependent_methods(klass_data);
+ return false;
+ }
+
NOT_PRODUCT( aot_klasses_found++; )
log_trace(aot, class, load)("found %s in %s for classloader %p tid=" INTPTR_FORMAT, kh->internal_name(), _lib->name(), kh->class_loader_data(), p2i(thread));
@@ -714,7 +724,7 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) {
// Set klass's Resolve (second) got cell.
_metaspace_got[klass_data->_got_index] = kh();
- // Initialize global symbols of the DSO to the correspondingVM symbol values.
+ // Initialize global symbols of the DSO to the corresponding VM symbol values.
link_global_lib_symbols();
int methods_offset = klass_data->_compiled_methods_offset;
diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.hpp b/hotspot/src/share/vm/aot/aotCodeHeap.hpp
index 21ce9a042f0..0e0d0038d10 100644
--- a/hotspot/src/share/vm/aot/aotCodeHeap.hpp
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.hpp
@@ -88,7 +88,7 @@ typedef struct {
} AOTHeader;
typedef struct {
- enum { CONFIG_SIZE = 11 + 7 * 4 };
+ enum { CONFIG_SIZE = 12 + 7 * 4 };
int _config_size;
int _narrowOopShift;
int _narrowKlassShift;
@@ -108,6 +108,7 @@ typedef struct {
bool _tieredAOT;
bool _enableContended;
bool _restrictContended;
+ bool _omitAssertions;
} AOTConfiguration;
class AOTLib : public CHeapObj {
diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
index 75a4f8aa3de..1a0a5f63687 100644
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -3298,7 +3298,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
// for osr compile, bailout if some requirements are not fulfilled
if (osr_bci != -1) {
BlockBegin* osr_block = blm.bci2block()->at(osr_bci);
- assert(osr_block->is_set(BlockBegin::was_visited_flag),"osr entry must have been visited for osr compile");
+ if (!osr_block->is_set(BlockBegin::was_visited_flag)) {
+ BAILOUT("osr entry must have been visited for osr compile");
+ }
// check if osr entry point has empty stack - we cannot handle non-empty stacks at osr entry points
if (!osr_block->state()->stack_is_empty()) {
diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp
index f7916cb1dab..e960d142abe 100644
--- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp
+++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp
@@ -895,8 +895,32 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
ciMethod* target = s.get_method(ignored_will_link, &declared_signature);
ciKlass* holder = s.get_declared_method_holder();
assert(declared_signature != NULL, "cannot be null");
- // Push appendix argument, if one.
- if (s.has_appendix()) {
+ // If the current bytecode has an attached appendix argument,
+ // push an unknown object to represent that argument. (Analysis
+ // of dynamic call sites, especially invokehandle calls, needs
+ // the appendix argument on the stack, in addition to "regular" arguments
+ // pushed onto the stack by bytecode instructions preceding the call.)
+ //
+ // The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s)
+ // method to determine whether the current bytecode has an appendix argument.
+ // The has_appendix() method obtains the appendix from the
+ // ConstantPoolCacheEntry::_f1 field, which can happen concurrently with
+ // resolution of dynamic call sites. Callees in the
+ // ciBytecodeStream::get_method() call above also access the _f1 field;
+ // interleaving the get_method() and has_appendix() calls in the current
+ // method with call site resolution can lead to an inconsistent view of
+ // the current method's argument count. In particular, some interleaving(s)
+ // can cause the method's argument count to not include the appendix, which
+ // then leads to stack over-/underflow in the escape analyzer.
+ //
+ // Instead of pushing the argument if has_appendix() is true, the escape analyzer
+ // pushes an appendix for all call sites targeted by invokedynamic and invokehandle
+ // instructions, except if the call site is the _invokeBasic intrinsic
+ // (that intrinsic is always targeted by an invokehandle instruction but does
+ // not have an appendix argument).
+ if (target->is_loaded() &&
+ Bytecodes::has_optional_appendix(s.cur_bc_raw()) &&
+ target->intrinsic_id() != vmIntrinsics::_invokeBasic) {
state.apush(unknown_obj);
}
// Pass in raw bytecode because we need to see invokehandle instructions.
diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp
index 2580f40f3ea..f16948e71d7 100644
--- a/hotspot/src/share/vm/ci/ciMethod.hpp
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp
@@ -136,15 +136,19 @@ class ciMethod : public ciMetadata {
check_is_loaded();
return _signature->size() + (_flags.is_static() ? 0 : 1);
}
- // Report the number of elements on stack when invoking this method.
- // This is different than the regular arg_size because invokedynamic
- // has an implicit receiver.
+ // Report the number of elements on stack when invoking the current method.
+ // If the method is loaded, arg_size() gives precise information about the
+ // number of stack elements (using the method's signature and its flags).
+ // However, if the method is not loaded, the number of stack elements must
+ // be determined differently, as the method's flags are not yet available.
+ // The invoke_arg_size() method assumes in that case that all bytecodes except
+ // invokestatic and invokedynamic have a receiver that is also pushed onto the
+ // stack by the caller of the current method.
int invoke_arg_size(Bytecodes::Code code) const {
if (is_loaded()) {
return arg_size();
} else {
int arg_size = _signature->size();
- // Add a receiver argument, maybe:
if (code != Bytecodes::_invokestatic &&
code != Bytecodes::_invokedynamic) {
arg_size++;
diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp
index e0b7c84e45b..0b036181d31 100644
--- a/hotspot/src/share/vm/classfile/classLoader.cpp
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -364,7 +364,12 @@ u1* ClassPathZipEntry::open_versioned_entry(const char* name, jint* filesize, TR
if (verstr != NULL) {
version = atoi(verstr);
if (version < base_version || version > cur_ver) {
- is_multi_ver = false;
+ // If the specified version is lower than the base version, the base
+ // entry will be used; if the version is higher than the current
+ // jdk version, the highest versioned entry will be used.
+ if (version < base_version) {
+ is_multi_ver = false;
+ }
// print out warning, do not use assertion here since it will continue to look
// for proper version.
warning("JDK%d is not supported in multiple version jars", version);
diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp
index fbafa936950..d1e37d82761 100644
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp
@@ -94,7 +94,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen
_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),
+ _next(NULL), _dependencies(dependencies),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
Monitor::_safepoint_check_never)) {
TRACE_INIT_ID(this);
diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp
index b69c4e681d4..8c8df5187a7 100644
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp
@@ -204,9 +204,6 @@ class ClassLoaderData : public CHeapObj {
// Support for walking class loader data objects
ClassLoaderData* _next; /// Next loader_datas created
- // CDS
- int _shared_class_loader_id;
-
// ReadOnly and ReadWrite metaspaces (static because only on the null
// class loader for now).
static Metaspace* _ro_metaspace;
@@ -338,15 +335,6 @@ class ClassLoaderData : public CHeapObj {
Metaspace* rw_metaspace();
void initialize_shared_metaspaces();
- int shared_class_loader_id() const {
- return _shared_class_loader_id;
- }
- void set_shared_class_loader_id(int id) {
- assert(id >= 0, "sanity");
- assert(_shared_class_loader_id <0, "cannot be assigned more than once");
- _shared_class_loader_id = id;
- }
-
TRACE_DEFINE_TRACE_ID_METHODS;
};
diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp
index 91b51404489..b7fe590eee1 100644
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp
@@ -163,8 +163,8 @@ void java_lang_String::compute_offsets() {
Klass* k = SystemDictionary::String_klass();
compute_offset(value_offset, k, vmSymbols::value_name(), vmSymbols::byte_array_signature());
- compute_optional_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature());
- compute_optional_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature());
+ compute_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature());
+ compute_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature());
initialized = true;
}
@@ -3977,12 +3977,8 @@ void JavaClasses::check_offsets() {
// java.lang.String
CHECK_OFFSET("java/lang/String", java_lang_String, value, "[B");
- if (java_lang_String::has_hash_field()) {
- CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I");
- }
- if (java_lang_String::has_coder_field()) {
- CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B");
- }
+ CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I");
+ CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B");
// java.lang.Class
diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp
index 0cf0090e851..f05db4c79b7 100644
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp
@@ -81,15 +81,6 @@ class java_lang_String : AllStatic {
static Handle create_from_platform_dependent_str(const char* str, TRAPS);
static Handle char_converter(Handle java_string, jchar from_char, jchar to_char, TRAPS);
- static bool has_hash_field() {
- assert(initialized, "Must be initialized");
- return (hash_offset > 0);
- }
- static bool has_coder_field() {
- assert(initialized, "Must be initialized");
- return (coder_offset > 0);
- }
-
static void set_compact_strings(bool value);
static int value_offset_in_bytes() {
diff --git a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp
index b1c4a3f9224..b388bb157d3 100644
--- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp
+++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp
@@ -30,10 +30,8 @@
#include "oops/oopsHierarchy.hpp"
void java_lang_String::set_coder(oop string, jbyte coder) {
- assert(initialized, "Must be initialized");
- if (coder_offset > 0) {
- string->byte_field_put(coder_offset, coder);
- }
+ assert(initialized && (coder_offset > 0), "Must be initialized");
+ string->byte_field_put(coder_offset, coder);
}
void java_lang_String::set_value_raw(oop string, typeArrayOop buffer) {
@@ -61,15 +59,11 @@ unsigned int java_lang_String::hash(oop java_string) {
return java_string->int_field(hash_offset);
}
bool java_lang_String::is_latin1(oop java_string) {
- assert(initialized, "Must be initialized");
+ assert(initialized && (coder_offset > 0), "Must be initialized");
assert(is_instance(java_string), "must be java_string");
- if (coder_offset > 0) {
- jbyte coder = java_string->byte_field(coder_offset);
- assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings");
- return coder == CODER_LATIN1;
- } else {
- return false;
- }
+ jbyte coder = java_string->byte_field(coder_offset);
+ assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings");
+ return coder == CODER_LATIN1;
}
int java_lang_String::length(oop java_string) {
assert(initialized, "Must be initialized");
diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp
index becda5363a6..afa3553af1c 100644
--- a/hotspot/src/share/vm/classfile/modules.cpp
+++ b/hotspot/src/share/vm/classfile/modules.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,8 +39,6 @@
#include "logging/log.hpp"
#include "memory/resourceArea.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"
@@ -48,17 +46,17 @@
#include "utilities/stringUtils.hpp"
#include "utilities/utf8.hpp"
-static bool verify_module_name(char *module_name) {
+static bool verify_module_name(const char *module_name) {
if (module_name == NULL) return false;
int len = (int)strlen(module_name);
return (len > 0 && len <= Symbol::max_length());
}
-bool Modules::verify_package_name(char *package_name) {
+bool Modules::verify_package_name(const 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) &&
+ UTF8::is_legal_utf8((const unsigned char *)package_name, len, false) &&
ClassFileParser::verify_unqualified_name(package_name, len,
ClassFileParser::LegalClass));
}
@@ -107,10 +105,8 @@ static ModuleEntry* get_module_entry(jobject module, TRAPS) {
return java_lang_reflect_Module::module_entry(module_h(), CHECK_NULL);
}
-static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring package, TRAPS) {
+static PackageEntry* get_package_entry(ModuleEntry* module_entry, const char* package_name, 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_data()->packages();
@@ -139,7 +135,8 @@ bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) {
}
static void define_javabase_module(jobject module, jstring version,
- jstring location, jobjectArray packages, TRAPS) {
+ jstring location, const char* const* packages,
+ jsize num_packages, TRAPS) {
ResourceMark rm(THREAD);
Handle module_handle(THREAD, JNIHandles::resolve(module));
@@ -164,21 +161,12 @@ static void define_javabase_module(jobject module, jstring 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* pkg_list = new GrowableArray(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_NAME);
- }
- char *package_name = java_lang_String::as_utf8_string(string_obj);
+ const char *package_name = packages[x];
if (!Modules::verify_package_name(package_name)) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name));
@@ -239,7 +227,7 @@ static void define_javabase_module(jobject module, jstring version,
}
}
if (duplicate_javabase) {
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+ THROW_MSG(vmSymbols::java_lang_InternalError(),
"Module " JAVA_BASE_NAME " is already defined");
}
@@ -262,13 +250,39 @@ static void define_javabase_module(jobject module, jstring version,
}
}
+// Caller needs ResourceMark.
+void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) {
+ const char* package_name = package->name()->as_C_string();
+ if (package->module()->is_named()) {
+ THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
+ err_msg("Package %s for module %s is already in another module, %s, defined to the class loader",
+ package_name, module_name, package->module()->name()->as_C_string()));
+ } else {
+ THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
+ err_msg("Package %s for module %s is already in the unnamed module defined to the class loader",
+ package_name, module_name));
+ }
+}
+
void Modules::define_module(jobject module, jstring version,
- jstring location, jobjectArray packages, TRAPS) {
+ jstring location, const char* const* packages,
+ jsize num_packages, TRAPS) {
ResourceMark rm(THREAD);
if (module == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object");
}
+
+ if (num_packages < 0) {
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+ "num_packages must be >= 0");
+ }
+
+ if (packages == NULL && num_packages > 0) {
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+ "num_packages should be zero if packages is null");
+ }
+
Handle module_handle(THREAD, JNIHandles::resolve(module));
if (!java_lang_reflect_Module::is_instance(module_handle())) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
@@ -283,7 +297,7 @@ void Modules::define_module(jobject module, jstring version,
// Special handling of java.base definition
if (strcmp(module_name, JAVA_BASE_NAME) == 0) {
- define_javabase_module(module, version, location, packages, CHECK);
+ define_javabase_module(module, version, location, packages, num_packages, CHECK);
return;
}
@@ -297,21 +311,11 @@ void Modules::define_module(jobject module, jstring version,
}
Handle h_loader = Handle(THREAD, loader);
- objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages));
- objArrayHandle packages_h(THREAD, packages_oop);
- int num_packages = (packages_h == NULL ? 0 : packages_h->length());
-
// Check that the list of packages has no duplicates and that the
// packages are syntactically ok.
GrowableArray* pkg_list = new GrowableArray(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);
+ const char* package_name = packages[x];
if (!verify_package_name(package_name)) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
err_msg("Invalid package name: %s for module: %s",
@@ -323,12 +327,15 @@ void Modules::define_module(jobject module, jstring version,
!SystemDictionary::is_platform_class_loader(h_loader) &&
strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) {
const char* class_loader_name = SystemDictionary::loader_name(h_loader());
- StringUtils::replace_no_expand(package_name, "/", ".");
+ size_t pkg_len = strlen(package_name);
+ char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len);
+ strncpy(pkg_name, package_name, pkg_len);
+ StringUtils::replace_no_expand(pkg_name, "/", ".");
const char* msg_text1 = "Class loader (instance of): ";
const char* msg_text2 = " tried to define prohibited package name: ";
- size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1;
+ size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1;
char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len);
- jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name);
+ jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
}
@@ -347,7 +354,6 @@ void Modules::define_module(jobject module, jstring version,
// 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.
@@ -373,6 +379,7 @@ void Modules::define_module(jobject module, jstring version,
assert(loader_data != NULL, "class loader data shouldn't be null");
PackageEntryTable* package_table = NULL;
+ PackageEntry* existing_pkg = NULL;
{
MutexLocker ml(Module_lock, THREAD);
@@ -382,13 +389,12 @@ void Modules::define_module(jobject module, jstring version,
// 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) {
+ existing_pkg = package_table->lookup_only(pkg_list->at(x));
+ if (existing_pkg != 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;
}
@@ -396,9 +402,8 @@ void Modules::define_module(jobject module, jstring version,
} // if (num_packages > 0)...
// Add the module and its packages.
- if (!dupl_modules && dupl_pkg_index == -1) {
+ if (!dupl_modules && existing_pkg == NULL) {
// 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);
@@ -426,13 +431,10 @@ void Modules::define_module(jobject module, jstring version,
// any errors ?
if (dupl_modules) {
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+ THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
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));
+ } else if (existing_pkg != NULL) {
+ throw_dup_pkg_exception(module_name, existing_pkg, CHECK);
}
if (log_is_enabled(Debug, modules)) {
@@ -497,8 +499,8 @@ void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) {
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) {
+void Modules::add_module_exports(jobject from_module, const char* package_name, jobject to_module, TRAPS) {
+ if (package_name == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
"package is null");
}
@@ -526,10 +528,9 @@ void Modules::add_module_exports(jobject from_module, jstring package, jobject t
}
}
- PackageEntry *package_entry = get_package_entry(from_module_entry, package, CHECK);
+ PackageEntry *package_entry = get_package_entry(from_module_entry, package_name, 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 : "",
@@ -557,7 +558,7 @@ void Modules::add_module_exports(jobject from_module, jstring package, jobject t
}
-void Modules::add_module_exports_qualified(jobject from_module, jstring package,
+void Modules::add_module_exports_qualified(jobject from_module, const char* package,
jobject to_module, TRAPS) {
if (to_module == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
@@ -649,21 +650,15 @@ jobject Modules::get_module(jclass clazz, TRAPS) {
}
-jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRAPS) {
+jobject Modules::get_module_by_package_name(jobject loader, const char* package_name, TRAPS) {
ResourceMark rm(THREAD);
assert(ModuleEntryTable::javabase_defined(),
"Attempt to call get_module_from_pkg before " JAVA_BASE_NAME " is defined");
- if (NULL == package) {
+ if (package_name == NULL) {
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.
@@ -672,7 +667,7 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA
"Class loader is not a subclass of java.lang.ClassLoader", JNI_FALSE);
}
- if (strlen(package_str) == 0) {
+ if (strlen(package_name) == 0) {
// Return the unnamed module
ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK_NULL);
if (NULL == module_table) return NULL;
@@ -680,24 +675,24 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA
return JNIHandles::make_local(THREAD, JNIHandles::resolve(unnamed_module->module()));
} else {
- TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
+ TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL);
return get_module(package_sym, h_loader, CHECK_NULL);
}
return NULL;
}
-jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) {
+jobject Modules::get_named_module(Handle h_loader, const char* package_name, TRAPS) {
assert(ModuleEntryTable::javabase_defined(),
"Attempt to call get_named_module before " JAVA_BASE_NAME " is defined");
assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()),
"Class loader is not a subclass of java.lang.ClassLoader");
- assert(package_str != NULL, "the package_str should not be NULL");
+ assert(package_name != NULL, "the package_name should not be NULL");
- if (strlen(package_str) == 0) {
+ if (strlen(package_name) == 0) {
return NULL;
}
- TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
+ TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL);
const PackageEntry* const pkg_entry =
get_package_entry_by_name(package_sym, h_loader, THREAD);
const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL);
@@ -723,14 +718,14 @@ jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) {
return NULL;
}
-void Modules::add_module_package(jobject module, jstring package, TRAPS) {
+void Modules::add_module_package(jobject module, const char* package_name, TRAPS) {
ResourceMark rm(THREAD);
if (module == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
"module is null");
}
- if (package == NULL) {
+ if (package_name == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
"package is null");
}
@@ -743,11 +738,6 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) {
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));
@@ -760,12 +750,15 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) {
!loader_data->is_platform_class_loader_data() &&
strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) {
const char* class_loader_name = SystemDictionary::loader_name(loader_data);
- StringUtils::replace_no_expand(package_name, "/", ".");
+ size_t pkg_len = strlen(package_name);
+ char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len);
+ strncpy(pkg_name, package_name, pkg_len);
+ StringUtils::replace_no_expand(pkg_name, "/", ".");
const char* msg_text1 = "Class loader (instance of): ";
const char* msg_text2 = " tried to define prohibited package name: ";
- size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1;
+ size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1;
char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len);
- jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name);
+ jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
}
@@ -776,31 +769,29 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) {
PackageEntryTable* package_table = loader_data->packages();
assert(package_table != NULL, "Missing package_table");
- bool pkg_exists = false;
+ PackageEntry* existing_pkg = NULL;
{
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)) {
+ existing_pkg = package_table->lookup_only(pkg_symbol);
+ if (existing_pkg == NULL) {
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));
+ if (existing_pkg != NULL) {
+ throw_dup_pkg_exception(module_entry->name()->as_C_string(), existing_pkg, CHECK);
}
}
// Export package in module to all unnamed modules.
-void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS) {
+void Modules::add_module_exports_to_all_unnamed(jobject module, const char* package_name, TRAPS) {
if (module == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
"module is null");
}
- if (package == NULL) {
+ if (package_name == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
"package is null");
}
@@ -811,10 +802,9 @@ void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package,
}
if (module_entry->is_named()) { // No-op for unnamed module.
- PackageEntry *package_entry = get_package_entry(module_entry, package, CHECK);
+ PackageEntry *package_entry = get_package_entry(module_entry, package_name, 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 : "",
@@ -833,10 +823,7 @@ void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package,
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();
- }
+ // Mark package as exported to all unnamed modules.
+ package_entry->set_is_exported_allUnnamed();
}
}
diff --git a/hotspot/src/share/vm/classfile/modules.hpp b/hotspot/src/share/vm/classfile/modules.hpp
index 25d02bf845c..4f5e089a065 100644
--- a/hotspot/src/share/vm/classfile/modules.hpp
+++ b/hotspot/src/share/vm/classfile/modules.hpp
@@ -48,9 +48,12 @@ public:
// * Packages contains a duplicate package name
// * A package already exists in another module for this class loader
// * Module is an unnamed module
+ // * num_packages is negative
+ // * num_packages is non-zero when packages is null
// NullPointerExceptions are thrown if module is null.
static void define_module(jobject module, jstring version,
- jstring location, jobjectArray packages, TRAPS);
+ jstring location, const char* const* packages,
+ jsize num_packages, TRAPS);
// Provides the java.lang.reflect.Module for the unnamed module defined
// to the boot loader.
@@ -72,7 +75,7 @@ public:
// * 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);
+ static void add_module_exports(jobject from_module, const char* 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 ".".
@@ -83,7 +86,7 @@ public:
// * 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);
+ static void add_module_exports_qualified(jobject from_module, const char* 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.
@@ -102,7 +105,7 @@ public:
// 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);
+ static jobject get_module_by_package_name(jobject loader, const char* package, TRAPS);
static jobject get_named_module(Handle h_loader, const char* package, TRAPS);
// If package is defined by loader, return the
@@ -116,16 +119,16 @@ public:
// * 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);
+ static void add_module_package(jobject module, const char* 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);
+ static void add_module_exports_to_all_unnamed(jobject module, const char* package, TRAPS);
// Return TRUE if package_name is syntactically valid, false otherwise.
- static bool verify_package_name(char *package_name);
+ static bool verify_package_name(const char *package_name);
// Return TRUE iff package is defined by loader
static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS);
diff --git a/hotspot/src/share/vm/classfile/packageEntry.cpp b/hotspot/src/share/vm/classfile/packageEntry.cpp
index 7ee6c52dd4e..ab80fcb732b 100644
--- a/hotspot/src/share/vm/classfile/packageEntry.cpp
+++ b/hotspot/src/share/vm/classfile/packageEntry.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,8 +37,8 @@
// Returns true if this package specifies m as a qualified export, including through an unnamed export
bool PackageEntry::is_qexported_to(ModuleEntry* m) const {
+ assert(Module_lock->owned_by_self(), "should have the Module_lock");
assert(m != NULL, "No module to lookup in this package's qualified exports list");
- MutexLocker m1(Module_lock);
if (is_exported_allUnnamed() && !m->is_named()) {
return true;
} else if (!has_qual_exports_list()) {
@@ -98,15 +98,8 @@ void PackageEntry::set_exported(ModuleEntry* m) {
}
if (m == NULL) {
- // NULL indicates the package is being unqualifiedly exported
- if (has_qual_exports_list()) {
- // 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
+ // NULL indicates the package is being unqualifiedly exported. Clean up
+ // the qualified list at the next safepoint.
set_unqual_exported();
} else {
@@ -115,14 +108,19 @@ void PackageEntry::set_exported(ModuleEntry* m) {
}
}
+// Set the package as exported to all unnamed modules unless the package is
+// already unqualifiedly exported.
void PackageEntry::set_is_exported_allUnnamed() {
MutexLocker m1(Module_lock);
if (!is_unqual_exported()) {
- _is_exported_allUnnamed = true;
+ _export_flags = PKG_EXP_ALLUNNAMED;
}
}
-// Remove dead module entries within the package's exported list.
+// Remove dead module entries within the package's exported list. Note that
+// if all of the modules on the _qualified_exports get purged the list does not
+// get deleted. This prevents the package from illegally transitioning from
+// exported to non-exported.
void PackageEntry::purge_qualified_exports() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
if (_must_walk_exports &&
@@ -160,18 +158,9 @@ void PackageEntry::purge_qualified_exports() {
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;
}
@@ -314,6 +303,11 @@ void PackageEntry::package_exports_do(ModuleClosure* const f) {
}
}
+bool PackageEntry::exported_pending_delete() const {
+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+ return (is_unqual_exported() && _qualified_exports != NULL);
+}
+
// Remove dead entries from all packages' exported list
void PackageEntryTable::purge_all_package_exports() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
@@ -344,13 +338,17 @@ void PackageEntryTable::print(outputStream* st) {
}
}
+// This function may be called from debuggers so access private fields directly
+// to prevent triggering locking-related asserts that could result from calling
+// getter methods.
void PackageEntry::print(outputStream* st) {
ResourceMark rm;
st->print_cr("package entry " PTR_FORMAT " name %s module %s classpath_index "
INT32_FORMAT " is_exported_unqualified %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_unqualified, _is_exported_allUnnamed, p2i(next()));
+ _classpath_index, _export_flags == PKG_EXP_UNQUALIFIED,
+ _export_flags == PKG_EXP_ALLUNNAMED, p2i(next()));
}
void PackageEntryTable::verify() {
diff --git a/hotspot/src/share/vm/classfile/packageEntry.hpp b/hotspot/src/share/vm/classfile/packageEntry.hpp
index a379bf9de3b..aaafa54bb6d 100644
--- a/hotspot/src/share/vm/classfile/packageEntry.hpp
+++ b/hotspot/src/share/vm/classfile/packageEntry.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,8 +34,8 @@
// 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 unqualifiedly
-// - a flag indicating if this package is exported to all unnamed modules.
+// - a field indicating if the package is exported unqualifiedly or to all
+// unnamed modules.
// - a growable array containing other module entries that this
// package is exported to.
//
@@ -44,9 +44,9 @@
// - qualified exports: the package has been explicitly qualified to at least
// one particular module or has been qualifiedly exported
// to all unnamed modules.
-// Note: _is_exported_allUnnamed is a form of a qualified
-// export. It is equivalent to the package being
-// explicitly exported to all current and future unnamed modules.
+// Note: being exported to all unnamed is a form of a qualified
+// export. It is equivalent to the package being explicitly
+// exported to all current and future unnamed modules.
// - unqualified exports: the package is exported to all modules.
//
// A package can transition from:
@@ -56,21 +56,53 @@
// A package cannot transition from:
// - being unqualifiedly exported, to exported qualifiedly to a specific module.
// This transition attempt is silently ignored in set_exported.
+// - being qualifiedly exported to not exported.
+// Because transitions are only allowed from less exposure to greater exposure,
+// the transition from qualifiedly exported to not exported would be considered
+// a backward direction. Therefore the implementation considers a package as
+// qualifiedly exported even if its export-list exists but is empty.
//
// The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either
// data structure.
+
+// PKG_EXP_UNQUALIFIED and PKG_EXP_ALLUNNAMED indicate whether the package is
+// exported unqualifiedly or exported to all unnamed modules. They are used to
+// set the value of _export_flags. Field _export_flags and the _qualified_exports
+// list are used to determine a package's export state.
+// Valid states are:
+//
+// 1. Package is not exported
+// _export_flags is zero and _qualified_exports is null
+// 2. Package is unqualifiedly exported
+// _export_flags is set to PKG_EXP_UNQUALIFIED
+// _qualified_exports may or may not be null depending on whether the package
+// transitioned from qualifiedly exported to unqualifiedly exported.
+// 3. Package is qualifiedly exported
+// _export_flags may be set to PKG_EXP_ALLUNNAMED if the package is also
+// exported to all unnamed modules
+// _qualified_exports will be non-null
+// 4. Package is exported to all unnamed modules
+// _export_flags is set to PKG_EXP_ALLUNNAMED
+// _qualified_exports may or may not be null depending on whether the package
+// is also qualifiedly exported to one or more named modules.
+#define PKG_EXP_UNQUALIFIED 0x0001
+#define PKG_EXP_ALLUNNAMED 0x0002
+#define PKG_EXP_UNQUALIFIED_OR_ALL_UNAMED (PKG_EXP_UNQUALIFIED | PKG_EXP_ALLUNNAMED)
+
class PackageEntry : public HashtableEntry {
private:
ModuleEntry* _module;
+ // Indicates if package is exported unqualifiedly or to all unnamed. Access to
+ // this field is protected by the Module_lock.
+ int _export_flags;
// 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_unqualified;
- bool _is_exported_allUnnamed;
bool _must_walk_exports;
- GrowableArray* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint
+ // Contains list of modules this package is qualifiedly exported to. Access
+ // to this list is protected by the Module_lock.
GrowableArray* _qualified_exports;
TRACE_DEFINE_TRACE_ID_FIELD;
@@ -80,17 +112,14 @@ private:
public:
void init() {
_module = NULL;
+ _export_flags = 0;
_classpath_index = -1;
- _is_exported_unqualified = false;
- _is_exported_allUnnamed = false;
_must_walk_exports = 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; }
@@ -98,37 +127,39 @@ public:
// package's export state
bool is_exported() const { // qualifiedly or unqualifiedly exported
- return (is_unqual_exported() || has_qual_exports_list() || is_exported_allUnnamed());
+ assert_locked_or_safepoint(Module_lock);
+ return ((_export_flags & PKG_EXP_UNQUALIFIED_OR_ALL_UNAMED) != 0) || has_qual_exports_list();
}
// Returns true if the package has any explicit qualified exports or is exported to all unnamed
bool is_qual_exported() const {
+ assert_locked_or_safepoint(Module_lock);
return (has_qual_exports_list() || is_exported_allUnnamed());
}
- // Returns true if there are any explicit qualified exports
+ // Returns true if there are any explicit qualified exports. Note that even
+ // if the _qualified_exports list is now empty (because the modules that were
+ // on the list got gc-ed and deleted from the list) this method may still
+ // return true.
bool has_qual_exports_list() const {
- assert(!(_qualified_exports != NULL && _is_exported_unqualified),
- "_qualified_exports set at same time as _is_exported_unqualified");
- return (_qualified_exports != NULL);
+ assert_locked_or_safepoint(Module_lock);
+ return (!is_unqual_exported() && _qualified_exports != NULL);
}
bool is_exported_allUnnamed() const {
- assert(!(_is_exported_allUnnamed && _is_exported_unqualified),
- "_is_exported_allUnnamed set at same time as _is_exported_unqualified");
- return _is_exported_allUnnamed;
+ assert_locked_or_safepoint(Module_lock);
+ return (_export_flags == PKG_EXP_ALLUNNAMED);
}
bool is_unqual_exported() const {
- assert(!(_qualified_exports != NULL && _is_exported_unqualified),
- "_qualified_exports set at same time as _is_exported_unqualified");
- assert(!(_is_exported_allUnnamed && _is_exported_unqualified),
- "_is_exported_allUnnamed set at same time as _is_exported_unqualified");
- return _is_exported_unqualified;
+ assert_locked_or_safepoint(Module_lock);
+ return (_export_flags == PKG_EXP_UNQUALIFIED);
}
+
+ // Explicitly set _export_flags to PKG_EXP_UNQUALIFIED and clear
+ // PKG_EXP_ALLUNNAMED, if it was set.
void set_unqual_exported() {
assert(Module_lock->owned_by_self(), "should have the Module_lock");
- _is_exported_unqualified = true;
- _is_exported_allUnnamed = false;
- _qualified_exports = NULL;
+ _export_flags = PKG_EXP_UNQUALIFIED;
}
- bool exported_pending_delete() const { return (_exported_pending_delete != NULL); }
+
+ bool exported_pending_delete() const;
void set_exported(ModuleEntry* m);
diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp
index 4da4869cef2..764e1eaa348 100644
--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp
+++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp
@@ -29,7 +29,6 @@
#include "classfile/dictionary.hpp"
class ClassFileStream;
-class SerializeClosure;
class SystemDictionaryShared: public SystemDictionary {
public:
@@ -79,8 +78,6 @@ public:
return NULL;
}
- static void serialize(SerializeClosure* soc) {}
-
// The (non-application) CDS implementation supports only classes in the boot
// class loader, which ensures that the verification constraints are the same
// during archive creation time and runtime. Thus we can do the constraint checks
diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp
index 3e902d9f18e..0ef86447c4e 100644
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp
@@ -590,11 +590,11 @@
template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \
template(java_lang_management_MemoryUsage, "java/lang/management/MemoryUsage") \
template(java_lang_management_ThreadInfo, "java/lang/management/ThreadInfo") \
+ template(jdk_internal_agent_Agent, "jdk/internal/agent/Agent") \
template(sun_management_Sensor, "sun/management/Sensor") \
- template(sun_management_Agent, "sun/management/Agent") \
+ template(sun_management_ManagementFactoryHelper, "sun/management/ManagementFactoryHelper") \
template(com_sun_management_internal_DiagnosticCommandImpl, "com/sun/management/internal/DiagnosticCommandImpl") \
template(com_sun_management_internal_GarbageCollectorExtImpl,"com/sun/management/internal/GarbageCollectorExtImpl") \
- template(sun_management_ManagementFactoryHelper, "sun/management/ManagementFactoryHelper") \
template(getDiagnosticCommandMBean_name, "getDiagnosticCommandMBean") \
template(getDiagnosticCommandMBean_signature, "()Lcom/sun/management/DiagnosticCommandMBean;") \
template(getGcInfoBuilder_name, "getGcInfoBuilder") \
diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp
index 80ce54f847e..bfe643ab683 100644
--- a/hotspot/src/share/vm/code/codeCache.cpp
+++ b/hotspot/src/share/vm/code/codeCache.cpp
@@ -149,16 +149,17 @@ void CodeCache::check_heap_sizes(size_t non_nmethod_size, size_t profiled_size,
size_t total_size = non_nmethod_size + profiled_size + non_profiled_size;
// Prepare error message
const char* error = "Invalid code heap sizes";
- err_msg message("NonNMethodCodeHeapSize (%zuK) + ProfiledCodeHeapSize (%zuK) + NonProfiledCodeHeapSize (%zuK) = %zuK",
+ err_msg message("NonNMethodCodeHeapSize (" SIZE_FORMAT "K) + ProfiledCodeHeapSize (" SIZE_FORMAT "K)"
+ " + NonProfiledCodeHeapSize (" SIZE_FORMAT "K) = " SIZE_FORMAT "K",
non_nmethod_size/K, profiled_size/K, non_profiled_size/K, total_size/K);
if (total_size > cache_size) {
// Some code heap sizes were explicitly set: total_size must be <= cache_size
- message.append(" is greater than ReservedCodeCacheSize (%zuK).", cache_size/K);
+ message.append(" is greater than ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K);
vm_exit_during_initialization(error, message);
} else if (all_set && total_size != cache_size) {
// All code heap sizes were explicitly set: total_size must equal cache_size
- message.append(" is not equal to ReservedCodeCacheSize (%zuK).", cache_size/K);
+ message.append(" is not equal to ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K);
vm_exit_during_initialization(error, message);
}
}
@@ -267,7 +268,7 @@ void CodeCache::initialize_heaps() {
uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3);
if (non_nmethod_size < (min_code_cache_size + code_buffers_size)) {
vm_exit_during_initialization(err_msg(
- "Not enough space in non-nmethod code heap to run VM: %zuK < %zuK",
+ "Not enough space in non-nmethod code heap to run VM: " SIZE_FORMAT "K < " SIZE_FORMAT "K",
non_nmethod_size/K, (min_code_cache_size + code_buffers_size)/K));
}
diff --git a/hotspot/src/share/vm/code/compiledMethod.hpp b/hotspot/src/share/vm/code/compiledMethod.hpp
index 863e8cfa610..f260835384a 100644
--- a/hotspot/src/share/vm/code/compiledMethod.hpp
+++ b/hotspot/src/share/vm/code/compiledMethod.hpp
@@ -250,7 +250,11 @@ public:
address insts_begin() const { return code_begin(); }
address insts_end() const { return stub_begin(); }
+ // Returns true if a given address is in the 'insts' section. The method
+ // insts_contains_inclusive() is end-inclusive.
bool insts_contains(address addr) const { return insts_begin() <= addr && addr < insts_end(); }
+ bool insts_contains_inclusive(address addr) const { return insts_begin() <= addr && addr <= insts_end(); }
+
int insts_size() const { return insts_end() - insts_begin(); }
virtual address consts_begin() const = 0;
diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp
index a0d379773eb..00c2e64f851 100644
--- a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp
+++ b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp
@@ -23,6 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/globals_extension.hpp"
#include "compiler/compilerDefinitions.hpp"
const char* compilertype2name_tab[compiler_number_of_types] = {
@@ -32,3 +34,82 @@ const char* compilertype2name_tab[compiler_number_of_types] = {
"jvmci",
"shark"
};
+
+#if defined(COMPILER2) || defined(SHARK)
+CompLevel CompLevel_highest_tier = CompLevel_full_optimization; // pure C2 and tiered or JVMCI and tiered
+#elif defined(COMPILER1)
+CompLevel CompLevel_highest_tier = CompLevel_simple; // pure C1 or JVMCI
+#else
+CompLevel CompLevel_highest_tier = CompLevel_none;
+#endif
+
+#if defined(TIERED)
+CompLevel CompLevel_initial_compile = CompLevel_full_profile; // tiered
+#elif defined(COMPILER1) || INCLUDE_JVMCI
+CompLevel CompLevel_initial_compile = CompLevel_simple; // pure C1 or JVMCI
+#elif defined(COMPILER2) || defined(SHARK)
+CompLevel CompLevel_initial_compile = CompLevel_full_optimization; // pure C2
+#else
+CompLevel CompLevel_initial_compile = CompLevel_none;
+#endif
+
+#if defined(COMPILER2)
+CompMode Compilation_mode = CompMode_server;
+#elif defined(COMPILER1)
+CompMode Compilation_mode = CompMode_client;
+#else
+CompMode Compilation_mode = CompMode_none;
+#endif
+
+#ifdef TIERED
+void set_client_compilation_mode() {
+ Compilation_mode = CompMode_client;
+ CompLevel_highest_tier = CompLevel_simple;
+ CompLevel_initial_compile = CompLevel_simple;
+ FLAG_SET_ERGO(bool, TieredCompilation, false);
+ FLAG_SET_ERGO(bool, ProfileInterpreter, false);
+#if INCLUDE_JVMCI
+ FLAG_SET_ERGO(bool, EnableJVMCI, false);
+ FLAG_SET_ERGO(bool, UseJVMCICompiler, false);
+#endif
+#if INCLUDE_AOT
+ FLAG_SET_ERGO(bool, UseAOT, false);
+#endif
+ if (FLAG_IS_DEFAULT(NeverActAsServerClassMachine)) {
+ FLAG_SET_ERGO(bool, NeverActAsServerClassMachine, true);
+ }
+ if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) {
+ FLAG_SET_ERGO(uintx, InitialCodeCacheSize, 160*K);
+ }
+ if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
+ FLAG_SET_ERGO(uintx, ReservedCodeCacheSize, 32*M);
+ }
+ if (FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) {
+ FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 27*M);
+ }
+ if (FLAG_IS_DEFAULT(ProfiledCodeHeapSize)) {
+ FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0);
+ }
+ if (FLAG_IS_DEFAULT(NonNMethodCodeHeapSize)) {
+ FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, 5*M);
+ }
+ if (FLAG_IS_DEFAULT(CodeCacheExpansionSize)) {
+ FLAG_SET_ERGO(uintx, CodeCacheExpansionSize, 32*K);
+ }
+ if (FLAG_IS_DEFAULT(MetaspaceSize)) {
+ FLAG_SET_ERGO(size_t, MetaspaceSize, 12*M);
+ }
+ if (FLAG_IS_DEFAULT(MaxRAM)) {
+ FLAG_SET_ERGO(uint64_t, MaxRAM, 1ULL*G);
+ }
+ if (FLAG_IS_DEFAULT(CompileThreshold)) {
+ FLAG_SET_ERGO(intx, CompileThreshold, 1500);
+ }
+ if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) {
+ FLAG_SET_ERGO(intx, OnStackReplacePercentage, 933);
+ }
+ if (FLAG_IS_DEFAULT(CICompilerCount)) {
+ FLAG_SET_ERGO(intx, CICompilerCount, 1);
+ }
+}
+#endif // TIERED
diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp
index 9a08a97b303..a2378ea1e92 100644
--- a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp
+++ b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp
@@ -54,27 +54,30 @@ enum CompLevel {
CompLevel_simple = 1, // C1
CompLevel_limited_profile = 2, // C1, invocation & backedge counters
CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo
- CompLevel_full_optimization = 4, // C2, Shark or JVMCI
-
-#if defined(COMPILER2) || defined(SHARK)
- CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered or JVMCI and tiered
-#elif defined(COMPILER1)
- CompLevel_highest_tier = CompLevel_simple, // pure C1 or JVMCI
-#else
- CompLevel_highest_tier = CompLevel_none,
-#endif
-
-#if defined(TIERED)
- CompLevel_initial_compile = CompLevel_full_profile // tiered
-#elif defined(COMPILER1) || INCLUDE_JVMCI
- CompLevel_initial_compile = CompLevel_simple // pure C1 or JVMCI
-#elif defined(COMPILER2) || defined(SHARK)
- CompLevel_initial_compile = CompLevel_full_optimization // pure C2
-#else
- CompLevel_initial_compile = CompLevel_none
-#endif
+ CompLevel_full_optimization = 4 // C2, Shark or JVMCI
};
+extern CompLevel CompLevel_highest_tier;
+extern CompLevel CompLevel_initial_compile;
+
+enum CompMode {
+ CompMode_none = 0,
+ CompMode_client = 1,
+ CompMode_server = 2
+};
+
+extern CompMode Compilation_mode;
+
+inline bool is_server_compilation_mode_vm() {
+ return Compilation_mode == CompMode_server;
+}
+
+inline bool is_client_compilation_mode_vm() {
+ return Compilation_mode == CompMode_client;
+}
+
+extern void set_client_compilation_mode();
+
inline bool is_c1_compile(int comp_level) {
return comp_level > CompLevel_none && comp_level < CompLevel_full_optimization;
}
diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp
index ed224cea90f..4388f348e92 100644
--- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp
+++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp
@@ -445,7 +445,9 @@ void DirectivesStack::init() {
_default_directives->_c1_store->EnableOption = true;
#endif
#ifdef COMPILER2
- _default_directives->_c2_store->EnableOption = true;
+ if (is_server_compilation_mode_vm()) {
+ _default_directives->_c2_store->EnableOption = true;
+ }
#endif
assert(error_msg == NULL, "Must succeed.");
push(_default_directives);
diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp
index 283fd48127e..7c4efa650a5 100644
--- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp
+++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp
@@ -60,13 +60,12 @@
cflags(BlockLayoutByFrequency, bool, BlockLayoutByFrequency, BlockLayoutByFrequency) \
cflags(PrintOptoAssembly, bool, PrintOptoAssembly, PrintOptoAssembly) \
cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \
- cflags(TraceOptoPipelining, bool, false, TraceOptoPipelining) \
- cflags(TraceOptoOutput, bool, false, TraceOptoOutput) \
+NOT_PRODUCT(cflags(TraceOptoPipelining, bool, TraceOptoPipelining, TraceOptoPipelining)) \
+NOT_PRODUCT(cflags(TraceOptoOutput, bool, TraceOptoOutput, TraceOptoOutput)) \
cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \
cflags(Vectorize, bool, false, Vectorize) \
cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \
cflags(CloneMapDebug, bool, false, CloneMapDebug) \
- cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \
cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \
cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit)
#else
diff --git a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp
index 42069703b27..93b07b21e2d 100644
--- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp
+++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -69,12 +69,12 @@ protected:
void initialize(HeapWord* bottom, HeapWord* end, size_t target_elem_size_in_bytes, size_t mapping_granularity_in_bytes) {
assert(mapping_granularity_in_bytes > 0, "just checking");
assert(is_power_of_2(mapping_granularity_in_bytes),
- "mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes);
+ "mapping granularity must be power of 2, is " SIZE_FORMAT, mapping_granularity_in_bytes);
assert((uintptr_t)bottom % mapping_granularity_in_bytes == 0,
- "bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT,
+ "bottom mapping area address must be a multiple of mapping granularity " SIZE_FORMAT ", is " PTR_FORMAT,
mapping_granularity_in_bytes, p2i(bottom));
assert((uintptr_t)end % mapping_granularity_in_bytes == 0,
- "end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT,
+ "end mapping area address must be a multiple of mapping granularity " SIZE_FORMAT ", is " PTR_FORMAT,
mapping_granularity_in_bytes, p2i(end));
size_t num_target_elems = pointer_delta(end, bottom, mapping_granularity_in_bytes);
idx_t bias = (uintptr_t)bottom / mapping_granularity_in_bytes;
diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp
index 4f2c46913db..737c57c117d 100644
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp
@@ -233,7 +233,7 @@ void CollectedHeap::pre_initialize() {
// Used for ReduceInitialCardMarks (when COMPILER2 is used);
// otherwise remains unused.
#if defined(COMPILER2) || INCLUDE_JVMCI
- _defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers()
+ _defer_initial_card_mark = is_server_compilation_mode_vm() && ReduceInitialCardMarks && can_elide_tlab_store_barriers()
&& (DeferInitialCardMark || card_mark_must_follow_store());
#else
assert(_defer_initial_card_mark == false, "Who would set it?");
diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
index 5248654f2f7..0119e115104 100644
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
@@ -1209,7 +1209,7 @@ void GenCollectedHeap::gc_epilogue(bool full) {
#if defined(COMPILER2) || INCLUDE_JVMCI
assert(DerivedPointerTable::is_empty(), "derived pointer present");
size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr()));
- guarantee(actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps");
+ guarantee(is_client_compilation_mode_vm() || actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps");
#endif /* COMPILER2 || INCLUDE_JVMCI */
resize_all_tlabs();
diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp
index 38df96ddd4c..5d6d160a4ee 100644
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp
@@ -57,11 +57,11 @@ void ReferenceProcessor::init_statics() {
java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock);
_always_clear_soft_ref_policy = new AlwaysClearPolicy();
-#if defined(COMPILER2) || INCLUDE_JVMCI
- _default_soft_ref_policy = new LRUMaxHeapPolicy();
-#else
- _default_soft_ref_policy = new LRUCurrentHeapPolicy();
-#endif
+ if (is_server_compilation_mode_vm()) {
+ _default_soft_ref_policy = new LRUMaxHeapPolicy();
+ } else {
+ _default_soft_ref_policy = new LRUCurrentHeapPolicy();
+ }
if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) {
vm_exit_during_initialization("Could not allocate reference policy object");
}
diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp
index 0df1ba020a2..b004ba58c89 100644
--- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp
+++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp
@@ -233,9 +233,11 @@ void ThreadLocalAllocBuffer::startup_initialization() {
// If the C2 compiler is not present, no space is reserved.
// +1 for rounding up to next cache line, +1 to be safe
- int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2;
- _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) /
- (int)HeapWordSize;
+ if (is_server_compilation_mode_vm()) {
+ int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2;
+ _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) /
+ (int)HeapWordSize;
+ }
#endif
// During jvm startup, the main (primordial) thread is initialized
diff --git a/hotspot/src/share/vm/interpreter/bytecode.cpp b/hotspot/src/share/vm/interpreter/bytecode.cpp
index 80b95d627b5..6cc38a5a0cd 100644
--- a/hotspot/src/share/vm/interpreter/bytecode.cpp
+++ b/hotspot/src/share/vm/interpreter/bytecode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -112,7 +112,7 @@ void Bytecode::assert_native_index(Bytecodes::Code bc, bool is_wide) {
// Implementation of Bytecode_tableupswitch
int Bytecode_tableswitch::dest_offset_at(int i) const {
- return get_Java_u4_at(aligned_offset(1 + (3 + i)*jintSize));
+ return get_aligned_Java_u4_at(1 + (3 + i)*jintSize);
}
diff --git a/hotspot/src/share/vm/interpreter/bytecode.hpp b/hotspot/src/share/vm/interpreter/bytecode.hpp
index f3fc9ea9d6a..5c53ab4121f 100644
--- a/hotspot/src/share/vm/interpreter/bytecode.hpp
+++ b/hotspot/src/share/vm/interpreter/bytecode.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,11 +45,11 @@ class Bytecode: public StackObj {
address addr_at (int offset) const { return (address)_bcp + offset; }
u_char byte_at(int offset) const { return *addr_at(offset); }
address aligned_addr_at (int offset) const { return (address)round_to((intptr_t)addr_at(offset), jintSize); }
- int aligned_offset (int offset) const { return aligned_addr_at(offset) - addr_at(0); }
// Word access:
int get_Java_u2_at (int offset) const { return Bytes::get_Java_u2(addr_at(offset)); }
int get_Java_u4_at (int offset) const { return Bytes::get_Java_u4(addr_at(offset)); }
+ int get_aligned_Java_u4_at(int offset) const { return Bytes::get_Java_u4(aligned_addr_at(offset)); }
int get_native_u2_at (int offset) const { return Bytes::get_native_u2(addr_at(offset)); }
int get_native_u4_at (int offset) const { return Bytes::get_native_u4(addr_at(offset)); }
@@ -150,8 +150,8 @@ class Bytecode_lookupswitch: public Bytecode {
void verify() const PRODUCT_RETURN;
// Attributes
- int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); }
- int number_of_pairs() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); }
+ int default_offset() const { return get_aligned_Java_u4_at(1 + 0*jintSize); }
+ int number_of_pairs() const { return get_aligned_Java_u4_at(1 + 1*jintSize); }
LookupswitchPair pair_at(int i) const {
assert(0 <= i && i < number_of_pairs(), "pair index out of bounds");
return LookupswitchPair(aligned_addr_at(1 + (1 + i)*2*jintSize));
@@ -166,9 +166,9 @@ class Bytecode_tableswitch: public Bytecode {
void verify() const PRODUCT_RETURN;
// Attributes
- int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); }
- int low_key() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); }
- int high_key() const { return get_Java_u4_at(aligned_offset(1 + 2*jintSize)); }
+ int default_offset() const { return get_aligned_Java_u4_at(1 + 0*jintSize); }
+ int low_key() const { return get_aligned_Java_u4_at(1 + 1*jintSize); }
+ int high_key() const { return get_aligned_Java_u4_at(1 + 2*jintSize); }
int dest_offset_at(int i) const;
int length() { return high_key()-low_key()+1; }
};
diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp
index 745fb5199ec..cca40f1aeb2 100644
--- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp
+++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp
@@ -554,7 +554,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle
_constants = buffer.consts();
initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK);
- JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK);
+ JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, false, CHECK_OK);
if (result != JVMCIEnv::ok) {
return result;
}
@@ -587,7 +587,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Hand
_constants = buffer.consts();
initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK);
- JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK);
+ JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, true, CHECK_OK);
if (result != JVMCIEnv::ok) {
return result;
}
@@ -726,7 +726,7 @@ int CodeInstaller::estimate_stubs_size(TRAPS) {
}
// perform data and call relocation on the CodeBuffer
-JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, TRAPS) {
+JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS) {
HandleMark hm;
objArrayHandle sites = this->sites();
int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo));
@@ -738,7 +738,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer,
int stubs_size = estimate_stubs_size(CHECK_OK);
int total_size = round_to(_code_size, buffer.insts()->alignment()) + round_to(_constants_size, buffer.consts()->alignment()) + round_to(stubs_size, buffer.stubs()->alignment());
- if (total_size > JVMCINMethodSizeLimit) {
+ if (check_size && total_size > JVMCINMethodSizeLimit) {
return JVMCIEnv::code_too_large;
}
@@ -1258,6 +1258,7 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, Handle site, T
case HEAP_TOP_ADDRESS:
case HEAP_END_ADDRESS:
case NARROW_KLASS_BASE_ADDRESS:
+ case NARROW_OOP_BASE_ADDRESS:
case CRC_TABLE_ADDRESS:
case LOG_OF_HEAP_REGION_GRAIN_BYTES:
case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp
index 775a8c19f40..a700174de1d 100644
--- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp
+++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp
@@ -133,9 +133,10 @@ private:
HEAP_TOP_ADDRESS = 17,
HEAP_END_ADDRESS = 18,
NARROW_KLASS_BASE_ADDRESS = 19,
- CRC_TABLE_ADDRESS = 20,
- LOG_OF_HEAP_REGION_GRAIN_BYTES = 21,
- INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 22,
+ NARROW_OOP_BASE_ADDRESS = 20,
+ CRC_TABLE_ADDRESS = 21,
+ LOG_OF_HEAP_REGION_GRAIN_BYTES = 22,
+ INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 23,
INVOKE_INVALID = -1
};
@@ -227,7 +228,7 @@ protected:
int estimate_stubs_size(TRAPS);
// perform data and call relocation on the CodeBuffer
- JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, TRAPS);
+ JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS);
void assumption_NoFinalizableSubclass(Handle assumption);
void assumption_ConcreteSubtype(Handle assumption);
diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp
index f7eb56ff404..2fe6b45b79e 100644
--- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp
+++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp
@@ -591,12 +591,16 @@ C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, job
return method->is_ignored_by_security_stack_walk();
C2V_END
-C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jobject jvmci_method))
+C2V_VMENTRY(jboolean, isCompilable,(JNIEnv *, jobject, jobject jvmci_method))
methodHandle method = CompilerToVM::asMethod(jvmci_method);
- // In hosted mode ignore the not_compilable flags since they are never set by
+ // Ignore the not_compilable flags in hosted mode since they are never set by
// the JVMCI compiler.
- bool is_compilable = UseJVMCICompiler ? !method->is_not_compilable(CompLevel_full_optimization) : true;
- return is_compilable && !CompilerOracle::should_not_inline(method) && !method->dont_inline();
+ return UseJVMCICompiler || !method->is_not_compilable(CompLevel_full_optimization);
+C2V_END
+
+C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv *, jobject, jobject jvmci_method))
+ methodHandle method = CompilerToVM::asMethod(jvmci_method);
+ return CompilerOracle::should_not_inline(method) || method->dont_inline();
C2V_END
C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method))
@@ -1591,7 +1595,8 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "getStackTraceElement", CC "(" HS_RESOLVED_METHOD "I)" STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)},
{CC "methodIsIgnoredBySecurityStackWalk", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)},
{CC "doNotInlineOrCompile", CC "(" HS_RESOLVED_METHOD ")V", FN_PTR(doNotInlineOrCompile)},
- {CC "canInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(canInlineMethod)},
+ {CC "isCompilable", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(isCompilable)},
+ {CC "hasNeverInlineDirective", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(hasNeverInlineDirective)},
{CC "shouldInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(shouldInlineMethod)},
{CC "lookupType", CC "(" STRING CLASS "Z)" HS_RESOLVED_KLASS, FN_PTR(lookupType)},
{CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupNameInPool)},
diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp
index 2dad27fdfd9..a01651f55aa 100644
--- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp
+++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp
@@ -429,6 +429,7 @@
declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \
declare_constant(CodeInstaller::HEAP_END_ADDRESS) \
declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \
+ declare_constant(CodeInstaller::NARROW_OOP_BASE_ADDRESS) \
declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \
declare_constant(CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES) \
declare_constant(CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED) \
@@ -534,7 +535,6 @@
\
declare_constant(markOopDesc::no_hash) \
\
- declare_constant(Method::_jfr_towrite) \
declare_constant(Method::_caller_sensitive) \
declare_constant(Method::_force_inline) \
declare_constant(Method::_dont_inline) \
diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp
index b8a5932ba0e..9b77b220e70 100644
--- a/hotspot/src/share/vm/logging/logConfiguration.cpp
+++ b/hotspot/src/share/vm/logging/logConfiguration.cpp
@@ -478,7 +478,7 @@ void LogConfiguration::describe(outputStream* out) {
void LogConfiguration::print_command_line_help(FILE* out) {
jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n"
- "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n"
+ "\t where 'what' is a combination of tags and levels of the form tag1[+tag2...][*][=level][,...]\n"
"\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n");
jio_fprintf(out, "Available log levels:\n");
@@ -514,6 +514,14 @@ void LogConfiguration::print_command_line_help(FILE* out) {
" -Xlog:gc\n"
"\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n"
+ " -Xlog:gc,safepoint\n"
+ "\t Log messages tagged either with 'gc' or 'safepoint' tags, both using 'info' level, to stdout, with default decorations.\n"
+ "\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)\n\n"
+
+ " -Xlog:gc+ref=debug\n"
+ "\t Log messages tagged with both 'gc' and 'ref' tags, using 'debug' level, to stdout, with default decorations.\n"
+ "\t (Messages tagged only with one of the two tags will not be logged.)\n\n"
+
" -Xlog:gc=debug:file=gc.txt:none\n"
"\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n"
diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp
index 61d6fa37b41..446517fd426 100644
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp
@@ -145,10 +145,6 @@ void MetaspaceShared::serialize(SerializeClosure* soc, GrowableArray
StringTable::serialize(soc, string_space, space_size);
soc->do_tag(--tag);
- // Dump/restore the misc information for system dictionary
- SystemDictionaryShared::serialize(soc);
- soc->do_tag(--tag);
-
soc->do_tag(666);
}
diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp
index 5b2180f945c..41f5fd143a8 100644
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2139,8 +2139,6 @@ void InstanceKlass::release_C_heap_structures(InstanceKlass* ik) {
}
void InstanceKlass::release_C_heap_structures() {
- assert(!this->is_shared(), "should not be called for a shared class");
-
// Can't release the constant pool here because the constant pool can be
// deallocated separately from the InstanceKlass for default methods and
// redefine classes.
@@ -2191,7 +2189,7 @@ void InstanceKlass::release_C_heap_structures() {
}
// deallocate the cached class file
- if (_cached_class_file != NULL) {
+ if (_cached_class_file != NULL && !MetaspaceShared::is_in_shared_space(_cached_class_file)) {
os::free(_cached_class_file);
_cached_class_file = NULL;
}
diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp
index 4e3dcf03bd8..f37278edd13 100644
--- a/hotspot/src/share/vm/oops/method.cpp
+++ b/hotspot/src/share/vm/oops/method.cpp
@@ -85,7 +85,6 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags) {
set_constMethod(xconst);
set_access_flags(access_flags);
set_intrinsic_id(vmIntrinsics::_none);
- set_jfr_towrite(false);
set_force_inline(false);
set_hidden(false);
set_dont_inline(false);
diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp
index 1c6e72df0fc..ebd5f0feef2 100644
--- a/hotspot/src/share/vm/oops/method.hpp
+++ b/hotspot/src/share/vm/oops/method.hpp
@@ -75,18 +75,19 @@ class Method : public Metadata {
// Flags
enum Flags {
- _jfr_towrite = 1 << 0,
- _caller_sensitive = 1 << 1,
- _force_inline = 1 << 2,
- _dont_inline = 1 << 3,
- _hidden = 1 << 4,
- _has_injected_profile = 1 << 5,
- _running_emcp = 1 << 6,
- _intrinsic_candidate = 1 << 7,
- _reserved_stack_access = 1 << 8
+ _caller_sensitive = 1 << 0,
+ _force_inline = 1 << 1,
+ _dont_inline = 1 << 2,
+ _hidden = 1 << 3,
+ _has_injected_profile = 1 << 4,
+ _running_emcp = 1 << 5,
+ _intrinsic_candidate = 1 << 6,
+ _reserved_stack_access = 1 << 7
};
mutable u2 _flags;
+ TRACE_DEFINE_FLAG;
+
#ifndef PRODUCT
int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging)
#endif
@@ -833,13 +834,6 @@ class Method : public Metadata {
void init_intrinsic_id(); // updates from _none if a match
static vmSymbols::SID klass_id_for_intrinsics(const Klass* holder);
- bool jfr_towrite() const {
- return (_flags & _jfr_towrite) != 0;
- }
- void set_jfr_towrite(bool x) const {
- _flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite);
- }
-
bool caller_sensitive() {
return (_flags & _caller_sensitive) != 0;
}
@@ -890,6 +884,8 @@ class Method : public Metadata {
_flags = x ? (_flags | _reserved_stack_access) : (_flags & ~_reserved_stack_access);
}
+ TRACE_DEFINE_FLAG_ACCESSOR;
+
ConstMethod::MethodType method_type() const {
return _constMethod->method_type();
}
diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp
index 85f7c9b6098..a99000aabcf 100644
--- a/hotspot/src/share/vm/oops/methodData.cpp
+++ b/hotspot/src/share/vm/oops/methodData.cpp
@@ -717,9 +717,9 @@ MethodData* MethodData::allocate(ClassLoaderData* loader_data, const methodHandl
}
int MethodData::bytecode_cell_count(Bytecodes::Code code) {
-#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI)
- return no_profile_data;
-#else
+ if (is_client_compilation_mode_vm()) {
+ return no_profile_data;
+ }
switch (code) {
case Bytecodes::_checkcast:
case Bytecodes::_instanceof:
@@ -778,7 +778,6 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) {
return variable_cell_count;
}
return no_profile_data;
-#endif
}
// Compute the size of the profiling information corresponding to
@@ -840,7 +839,9 @@ bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) {
case Bytecodes::_ifnonnull:
case Bytecodes::_invokestatic:
#ifdef COMPILER2
- return UseTypeSpeculation;
+ if (is_server_compilation_mode_vm()) {
+ return UseTypeSpeculation;
+ }
#endif
default:
return false;
@@ -942,9 +943,9 @@ int MethodData::compute_allocation_size_in_words(const methodHandle& method) {
// the segment in bytes.
int MethodData::initialize_data(BytecodeStream* stream,
int data_index) {
-#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI)
- return 0;
-#else
+ if (is_client_compilation_mode_vm()) {
+ return 0;
+ }
int cell_count = -1;
int tag = DataLayout::no_tag;
DataLayout* data_layout = data_layout_at(data_index);
@@ -1061,7 +1062,6 @@ int MethodData::initialize_data(BytecodeStream* stream,
assert(!bytecode_has_profile(c), "agree w/ !BHP");
return 0;
}
-#endif
}
// Get the data at an arbitrary (sort of) data index.
diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp
index a85b64e8801..627fba527e2 100644
--- a/hotspot/src/share/vm/oops/methodData.hpp
+++ b/hotspot/src/share/vm/oops/methodData.hpp
@@ -2183,7 +2183,7 @@ private:
uint _nof_overflow_traps; // trap count, excluding _trap_hist
union {
intptr_t _align;
- u1 _array[_trap_hist_limit];
+ u1 _array[JVMCI_ONLY(2 *) _trap_hist_limit];
} _trap_hist;
// Support for interprocedural escape analysis, from Thomas Kotzmann.
diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp
index 47606b6a599..de85b1cb155 100644
--- a/hotspot/src/share/vm/opto/cfgnode.cpp
+++ b/hotspot/src/share/vm/opto/cfgnode.cpp
@@ -2097,6 +2097,7 @@ const RegMask &PhiNode::out_RegMask() const {
uint ideal_reg = _type->ideal_reg();
assert( ideal_reg != Node::NotAMachineReg, "invalid type at Phi" );
if( ideal_reg == 0 ) return RegMask::Empty;
+ assert(ideal_reg != Op_RegFlags, "flags register is not spillable");
return *(Compile::current()->matcher()->idealreg2spillmask[ideal_reg]);
}
diff --git a/hotspot/src/share/vm/opto/coalesce.cpp b/hotspot/src/share/vm/opto/coalesce.cpp
index 1e8af4e27ee..fb45d92df42 100644
--- a/hotspot/src/share/vm/opto/coalesce.cpp
+++ b/hotspot/src/share/vm/opto/coalesce.cpp
@@ -292,7 +292,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
// Copy any flags as well
_phc.clone_projs(pred, pred->end_idx(), m, copy, _phc._lrg_map);
} else {
- const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()];
+ int ireg = m->ideal_reg();
+ if (ireg == 0 || ireg == Op_RegFlags) {
+ assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s",
+ m->_idx, m->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::PhiInput));
+ C->record_method_not_compilable("attempted to spill a non-spillable item");
+ return;
+ }
+ const RegMask *rm = C->matcher()->idealreg2spillmask[ireg];
copy = new MachSpillCopyNode(MachSpillCopyNode::PhiInput, m, *rm, *rm);
// Find a good place to insert. Kinda tricky, use a subroutine
insert_copy_with_overlap(pred,copy,phi_name,src_name);
@@ -326,7 +333,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
b->insert_node(copy, l++);
l += _phc.clone_projs(b, l, m, copy, _phc._lrg_map);
} else {
- const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()];
+ int ireg = m->ideal_reg();
+ if (ireg == 0 || ireg == Op_RegFlags) {
+ assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s",
+ m->_idx, m->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::TwoAddress));
+ C->record_method_not_compilable("attempted to spill a non-spillable item");
+ return;
+ }
+ const RegMask *rm = C->matcher()->idealreg2spillmask[ireg];
copy = new MachSpillCopyNode(MachSpillCopyNode::TwoAddress, m, *rm, *rm);
// Insert the copy in the basic block, just before us
b->insert_node(copy, l++);
@@ -373,7 +387,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
if( k < b->_num_succs )
continue; // Live out; do not pre-split
// Split the lrg at this use
- const RegMask *rm = C->matcher()->idealreg2spillmask[inp->ideal_reg()];
+ int ireg = inp->ideal_reg();
+ if (ireg == 0 || ireg == Op_RegFlags) {
+ assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s",
+ inp->_idx, inp->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::DebugUse));
+ C->record_method_not_compilable("attempted to spill a non-spillable item");
+ return;
+ }
+ const RegMask *rm = C->matcher()->idealreg2spillmask[ireg];
Node* copy = new MachSpillCopyNode(MachSpillCopyNode::DebugUse, inp, *rm, *rm);
// Insert the copy in the use-def chain
n->set_req(inpidx, copy );
diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp
index 77e20b264cb..4c84b0339ec 100644
--- a/hotspot/src/share/vm/opto/compile.cpp
+++ b/hotspot/src/share/vm/opto/compile.cpp
@@ -971,7 +971,7 @@ Compile::Compile( ciEnv* ci_env,
_java_calls(0),
_inner_loops(0),
#ifndef PRODUCT
- _trace_opto_output(TraceOptoOutput),
+ _trace_opto_output(directive->TraceOptoOutputOption),
_in_dump_cnt(0),
_printer(NULL),
#endif
diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp
index c879137d882..1c328b7bb75 100644
--- a/hotspot/src/share/vm/opto/graphKit.cpp
+++ b/hotspot/src/share/vm/opto/graphKit.cpp
@@ -3152,19 +3152,6 @@ Node* GraphKit::insert_mem_bar_volatile(int opcode, int alias_idx, Node* precede
return membar;
}
-void GraphKit::insert_store_load_for_barrier() {
- Node* mem = reset_memory();
- MemBarNode* mb = MemBarNode::make(C, Op_MemBarVolatile, Compile::AliasIdxBot);
- mb->init_req(TypeFunc::Control, control());
- mb->init_req(TypeFunc::Memory, mem);
- Node* membar = _gvn.transform(mb);
- set_control(_gvn.transform(new ProjNode(membar, TypeFunc::Control)));
- Node* newmem = _gvn.transform(new ProjNode(membar, TypeFunc::Memory));
- set_all_memory(mem);
- set_memory(newmem, Compile::AliasIdxRaw);
-}
-
-
//------------------------------shared_lock------------------------------------
// Emit locking code.
FastLockNode* GraphKit::shared_lock(Node* obj) {
@@ -3854,7 +3841,7 @@ void GraphKit::write_barrier_post(Node* oop_store,
BasicType bt = T_BYTE;
if (UseConcMarkSweepGC && UseCondCardMark) {
- insert_store_load_for_barrier();
+ insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier
__ sync_kit(this);
}
@@ -4294,7 +4281,8 @@ void GraphKit::g1_write_barrier_post(Node* oop_store,
__ if_then(card_val, BoolTest::ne, young_card); {
sync_kit(ideal);
- insert_store_load_for_barrier();
+ // Use Op_MemBarVolatile to achieve the effect of a StoreLoad barrier.
+ insert_mem_bar(Op_MemBarVolatile, oop_store);
__ sync_kit(this);
Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw);
@@ -4348,20 +4336,16 @@ Node* GraphKit::load_String_value(Node* ctrl, Node* str) {
}
Node* GraphKit::load_String_coder(Node* ctrl, Node* str) {
- if (java_lang_String::has_coder_field()) {
- if (!CompactStrings) {
- return intcon(java_lang_String::CODER_UTF16);
- }
- int coder_offset = java_lang_String::coder_offset_in_bytes();
- const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
- false, NULL, 0);
- const TypePtr* coder_field_type = string_type->add_offset(coder_offset);
- int coder_field_idx = C->get_alias_index(coder_field_type);
- return make_load(ctrl, basic_plus_adr(str, str, coder_offset),
- TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered);
- } else {
- return intcon(0); // false
+ if (!CompactStrings) {
+ return intcon(java_lang_String::CODER_UTF16);
}
+ int coder_offset = java_lang_String::coder_offset_in_bytes();
+ const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
+ false, NULL, 0);
+ const TypePtr* coder_field_type = string_type->add_offset(coder_offset);
+ int coder_field_idx = C->get_alias_index(coder_field_type);
+ return make_load(ctrl, basic_plus_adr(str, str, coder_offset),
+ TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered);
}
void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) {
diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp
index 6d60539b527..cbae7ce3761 100644
--- a/hotspot/src/share/vm/opto/graphKit.hpp
+++ b/hotspot/src/share/vm/opto/graphKit.hpp
@@ -837,7 +837,6 @@ class GraphKit : public Phase {
int next_monitor();
Node* insert_mem_bar(int opcode, Node* precedent = NULL);
Node* insert_mem_bar_volatile(int opcode, int alias_idx, Node* precedent = NULL);
- void insert_store_load_for_barrier();
// Optional 'precedent' is appended as an extra edge, to force ordering.
FastLockNode* shared_lock(Node* obj);
void shared_unlock(Node* box, Node* obj);
diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp
index c298e318ab5..5d837d6ecb0 100644
--- a/hotspot/src/share/vm/opto/library_call.cpp
+++ b/hotspot/src/share/vm/opto/library_call.cpp
@@ -6335,7 +6335,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) {
//------------------------------get_key_start_from_aescrypt_object-----------------------
Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) {
-#ifdef PPC64
+#if defined(PPC64) || defined(S390)
// MixColumns for decryption can be reduced by preprocessing MixColumns with round keys.
// Intel's extention is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns.
// However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption.
diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp
index cd0839c3294..07f791d05d1 100644
--- a/hotspot/src/share/vm/opto/machnode.cpp
+++ b/hotspot/src/share/vm/opto/machnode.cpp
@@ -643,6 +643,7 @@ const RegMask &MachSafePointNode::in_RegMask( uint idx ) const {
}
// Values outside the domain represent debug info
+ assert(in(idx)->ideal_reg() != Op_RegFlags, "flags register is not spillable");
return *Compile::current()->matcher()->idealreg2spillmask[in(idx)->ideal_reg()];
}
diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp
index 9bae43a4e28..bd0a1b75c9a 100644
--- a/hotspot/src/share/vm/opto/macro.cpp
+++ b/hotspot/src/share/vm/opto/macro.cpp
@@ -426,7 +426,7 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me
// Generate loads from source of the arraycopy for fields of
// destination needed at a deoptimization point
-Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, BasicType ft, const Type *ftype, AllocateNode *alloc) {
+Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type *ftype, AllocateNode *alloc) {
BasicType bt = ft;
const Type *type = ftype;
if (ft == T_NARROWOOP) {
@@ -438,8 +438,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset,
Node* base = ac->in(ArrayCopyNode::Src)->in(AddPNode::Base);
Node* adr = _igvn.transform(new AddPNode(base, base, MakeConX(offset)));
const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset);
- Node* m = ac->in(TypeFunc::Memory);
- res = LoadNode::make(_igvn, ctl, m, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned);
+ res = LoadNode::make(_igvn, ctl, mem, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned);
} else {
if (ac->modifies(offset, offset, &_igvn, true)) {
assert(ac->in(ArrayCopyNode::Dest) == alloc->result_cast(), "arraycopy destination should be allocation's result");
@@ -454,8 +453,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset,
Node* base = ac->in(ArrayCopyNode::Src);
Node* adr = _igvn.transform(new AddPNode(base, base, off));
const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset);
- Node* m = ac->in(TypeFunc::Memory);
- res = LoadNode::make(_igvn, ctl, m, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned);
+ res = LoadNode::make(_igvn, ctl, mem, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned);
}
}
if (res != NULL) {
@@ -544,7 +542,7 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
assert(false, "Object is not scalar replaceable if a LoadStore node accesses its field");
return NULL;
} else if (val->is_ArrayCopy()) {
- Node* res = make_arraycopy_load(val->as_ArrayCopy(), offset, val->in(0), ft, phi_type, alloc);
+ Node* res = make_arraycopy_load(val->as_ArrayCopy(), offset, val->in(0), val->in(TypeFunc::Memory), ft, phi_type, alloc);
if (res == NULL) {
return NULL;
}
@@ -657,11 +655,13 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType
}
} else if (mem->is_ArrayCopy()) {
Node* ctl = mem->in(0);
+ Node* m = mem->in(TypeFunc::Memory);
if (sfpt_ctl->is_Proj() && sfpt_ctl->as_Proj()->is_uncommon_trap_proj(Deoptimization::Reason_none)) {
// pin the loads in the uncommon trap path
ctl = sfpt_ctl;
+ m = sfpt_mem;
}
- return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, ft, ftype, alloc);
+ return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, m, ft, ftype, alloc);
}
}
// Something go wrong.
diff --git a/hotspot/src/share/vm/opto/macro.hpp b/hotspot/src/share/vm/opto/macro.hpp
index ba8e9eac8e4..5482a1d8282 100644
--- a/hotspot/src/share/vm/opto/macro.hpp
+++ b/hotspot/src/share/vm/opto/macro.hpp
@@ -200,7 +200,7 @@ private:
Node* old_eden_top, Node* new_eden_top,
Node* length);
- Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, BasicType ft, const Type *ftype, AllocateNode *alloc);
+ Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type *ftype, AllocateNode *alloc);
public:
PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn), _has_locks(false) {
diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp
index 7c7ed8dd493..698b0bae068 100644
--- a/hotspot/src/share/vm/opto/matcher.cpp
+++ b/hotspot/src/share/vm/opto/matcher.cpp
@@ -85,6 +85,7 @@ Matcher::Matcher()
idealreg2spillmask [Op_VecX] = NULL;
idealreg2spillmask [Op_VecY] = NULL;
idealreg2spillmask [Op_VecZ] = NULL;
+ idealreg2spillmask [Op_RegFlags] = NULL;
idealreg2debugmask [Op_RegI] = NULL;
idealreg2debugmask [Op_RegN] = NULL;
@@ -97,6 +98,7 @@ Matcher::Matcher()
idealreg2debugmask [Op_VecX] = NULL;
idealreg2debugmask [Op_VecY] = NULL;
idealreg2debugmask [Op_VecZ] = NULL;
+ idealreg2debugmask [Op_RegFlags] = NULL;
idealreg2mhdebugmask[Op_RegI] = NULL;
idealreg2mhdebugmask[Op_RegN] = NULL;
@@ -109,6 +111,7 @@ Matcher::Matcher()
idealreg2mhdebugmask[Op_VecX] = NULL;
idealreg2mhdebugmask[Op_VecY] = NULL;
idealreg2mhdebugmask[Op_VecZ] = NULL;
+ idealreg2mhdebugmask[Op_RegFlags] = NULL;
debug_only(_mem_node = NULL;) // Ideal memory node consumed by mach node
}
diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp
index 6e92398898a..5f516c5e7e2 100644
--- a/hotspot/src/share/vm/precompiled/precompiled.hpp
+++ b/hotspot/src/share/vm/precompiled/precompiled.hpp
@@ -23,7 +23,7 @@
*/
// Precompiled headers are turned off for Sun Studion,
-// or if the user passes USE_PRECOMPILED_HEADER=0 to the makefiles.
+// or if the user passes --disable-precompiled-headers to configure.
#ifndef DONT_USE_PRECOMPILED_HEADER
# include "asm/assembler.hpp"
diff --git a/hotspot/src/share/vm/prims/jniCheck.cpp b/hotspot/src/share/vm/prims/jniCheck.cpp
index ea80b5b8110..9ba9e1ad419 100644
--- a/hotspot/src/share/vm/prims/jniCheck.cpp
+++ b/hotspot/src/share/vm/prims/jniCheck.cpp
@@ -238,8 +238,8 @@ functionExit(JavaThread* thr)
size_t live_handles = handles->get_number_of_live_handles();
if (live_handles > planned_capacity) {
IN_VM(
- tty->print_cr("WARNING: JNI local refs: %zu, exceeds capacity: %zu",
- live_handles, planned_capacity);
+ tty->print_cr("WARNING: JNI local refs: " SIZE_FORMAT ", exceeds capacity: " SIZE_FORMAT,
+ live_handles, planned_capacity);
thr->print_stack();
)
// Complain just the once, reset to current + warn threshold
diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp
index 6a1b4dda087..2955463852e 100644
--- a/hotspot/src/share/vm/prims/jvm.cpp
+++ b/hotspot/src/share/vm/prims/jvm.cpp
@@ -1009,9 +1009,9 @@ JVM_END
// Module support //////////////////////////////////////////////////////////////////////////////
JVM_ENTRY(void, JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version,
- jstring location, jobjectArray packages))
+ jstring location, const char* const* packages, jsize num_packages))
JVMWrapper("JVM_DefineModule");
- Modules::define_module(module, version, location, packages, CHECK);
+ Modules::define_module(module, version, location, packages, num_packages, CHECK);
JVM_END
JVM_ENTRY(void, JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module))
@@ -1019,17 +1019,17 @@ JVM_ENTRY(void, JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module))
Modules::set_bootloader_unnamed_module(module, CHECK);
JVM_END
-JVM_ENTRY(void, JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module))
+JVM_ENTRY(void, JVM_AddModuleExports(JNIEnv *env, jobject from_module, const char* package, jobject to_module))
JVMWrapper("JVM_AddModuleExports");
Modules::add_module_exports_qualified(from_module, package, to_module, CHECK);
JVM_END
-JVM_ENTRY(void, JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package))
+JVM_ENTRY(void, JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, const char* package))
JVMWrapper("JVM_AddModuleExportsToAllUnnamed");
Modules::add_module_exports_to_all_unnamed(from_module, package, CHECK);
JVM_END
-JVM_ENTRY(void, JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package))
+JVM_ENTRY(void, JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, const char* package))
JVMWrapper("JVM_AddModuleExportsToAll");
Modules::add_module_exports(from_module, package, NULL, CHECK);
JVM_END
@@ -1039,16 +1039,11 @@ JVM_ENTRY (void, JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject so
Modules::add_reads_module(from_module, source_module, CHECK);
JVM_END
-JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, jstring package))
+JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, const char* package))
JVMWrapper("JVM_AddModulePackage");
Modules::add_module_package(module, package, CHECK);
JVM_END
-JVM_ENTRY (jobject, JVM_GetModuleByPackageName(JNIEnv *env, jobject loader, jstring package))
- JVMWrapper("JVM_GetModuleByPackageName");
- return Modules::get_module_by_package_name(loader, package, THREAD);
-JVM_END
-
// Reflection support //////////////////////////////////////////////////////////////////////////////
JVM_ENTRY(jstring, JVM_GetClassName(JNIEnv *env, jclass cls))
diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h
index c713645024e..e105c97766d 100644
--- a/hotspot/src/share/vm/prims/jvm.h
+++ b/hotspot/src/share/vm/prims/jvm.h
@@ -412,30 +412,67 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader,
* Module support funcions
*/
+/*
+ * Define a module with the specified packages and bind the module to the
+ * given class loader.
+ * module: module to define
+ * is_open: specifies if module is open (currently ignored)
+ * version: the module version
+ * location: the module location
+ * packages: list of packages in the module
+ * num_packages: number of packages in the module
+ */
JNIEXPORT void JNICALL
JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version,
- jstring location, jobjectArray packages);
+ jstring location, const char* const* packages, jsize num_packages);
+/*
+ * Set the boot loader's unnamed module.
+ * module: boot loader's unnamed module
+ */
JNIEXPORT void JNICALL
JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module);
+/*
+ * Do a qualified export of a package.
+ * from_module: module containing the package to export
+ * package: name of the package to export
+ * to_module: module to export the package to
+ */
JNIEXPORT void JNICALL
-JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module);
+JVM_AddModuleExports(JNIEnv *env, jobject from_module, const char* package, jobject to_module);
+/*
+ * Do an export of a package to all unnamed modules.
+ * from_module: module containing the package to export
+ * package: name of the package to export to all unnamed modules
+ */
JNIEXPORT void JNICALL
-JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package);
+JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, const char* package);
+/*
+ * Do an unqualified export of a package.
+ * from_module: module containing the package to export
+ * package: name of the package to export
+ */
JNIEXPORT void JNICALL
-JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package);
+JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, const char* package);
+/*
+ * Add a module to the list of modules that a given module can read.
+ * from_module: module requesting read access
+ * source_module: module that from_module wants to read
+ */
JNIEXPORT void JNICALL
JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module);
+/*
+ * Add a package to a module.
+ * module: module that will contain the package
+ * package: package to add to the module
+ */
JNIEXPORT void JNICALL
-JVM_AddModulePackage(JNIEnv* env, jobject module, jstring package);
-
-JNIEXPORT jobject JNICALL
-JVM_GetModuleByPackageName(JNIEnv* env, jobject loader, jstring package);
+JVM_AddModulePackage(JNIEnv* env, jobject module, const char* package);
/*
* Reflection support functions
diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml
index 0f390214eb2..7a0515c2bc4 100644
--- a/hotspot/src/share/vm/prims/jvmti.xml
+++ b/hotspot/src/share/vm/prims/jvmti.xml
@@ -1,7 +1,7 @@
defines first_mod --> no packages
+// defines second_mod --> packages p2
+//
+// first_mod can read second_mod
+// package p2 in second_mod is exported to first_mod
+//
+// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in second_mod
+// Access is not allowed, even after p2 is exported to all unnamed modules.
+
+public class AccessExportTwice {
+
+ // Create a Layer over the boot layer.
+ // Define modules within this layer to test access between
+ // publicly defined classes within packages of those modules.
+ public void createLayerOnBoot() throws Throwable {
+
+ // Define module: first_mod
+ // Can read: java.base, second_mod
+ // Packages: none
+ // Packages exported: none
+ ModuleDescriptor descriptor_first_mod =
+ ModuleDescriptor.module("first_mod")
+ .requires("java.base")
+ .requires("second_mod")
+ .build();
+
+ // Define module: second_mod
+ // Can read: java.base
+ // Packages: p2
+ // Packages exported: p2 is exported to first_mod
+ ModuleDescriptor descriptor_second_mod =
+ ModuleDescriptor.module("second_mod")
+ .requires("java.base")
+ .exports("p2", Set.of("first_mod"))
+ .build();
+
+ // Set up a ModuleFinder containing all modules for this layer
+ ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod);
+
+ // Resolves "first_mod"
+ Configuration cf = Layer.boot()
+ .configuration()
+ .resolveRequires(finder, ModuleFinder.of(), Set.of("first_mod"));
+
+ // Map each module to the same class loader
+ Map map = new HashMap<>();
+ map.put("first_mod", MySameClassLoader.loader1);
+ map.put("second_mod", MySameClassLoader.loader1);
+
+ // Create Layer that contains first_mod & second_mod
+ Layer layer = Layer.boot().defineModules(cf, map::get);
+
+ assertTrue(layer.findLoader("first_mod") == MySameClassLoader.loader1);
+ assertTrue(layer.findLoader("second_mod") == MySameClassLoader.loader1);
+ assertTrue(layer.findLoader("java.base") == null);
+
+ Class p2_c2_class = MySameClassLoader.loader1.loadClass("p2.c2");
+ // Use the same loader to load class p1.c1
+ Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1");
+ // First access check for p1.c1
+ try {
+ p1_c1_class.newInstance();
+ throw new RuntimeException("Test Failed, the unnamed module should not have access to public type p2.c2");
+ } catch (IllegalAccessError e) {
+ String message = e.getMessage();
+ if (!(message.contains("cannot access") &&
+ message.contains("because module second_mod does not export p2 to unnamed module"))) {
+ throw new RuntimeException("Wrong message: " + message);
+ } else {
+ System.out.println("Test Succeeded at attempt #1");
+ }
+ }
+
+ // Export second_mod/p2 to all unnamed modules.
+ Module second_mod = p2_c2_class.getModule();
+ jdk.internal.module.Modules.addExportsToAllUnnamed(second_mod, "p2");
+
+ // Second access check for p1.c1, should have same result as first
+ try {
+ p1_c1_class.newInstance();
+ throw new RuntimeException("Test Failed, access should have been cached above");
+ } catch (IllegalAccessError e) {
+ String message = e.getMessage();
+ if (!(message.contains("cannot access") &&
+ message.contains("because module second_mod does not export p2 to unnamed module"))) {
+ throw new RuntimeException("Wrong message: " + message);
+ } else {
+ System.out.println("Test Succeeded at attempt #2");
+ }
+ }
+ }
+
+ public static void main(String args[]) throws Throwable {
+ AccessExportTwice test = new AccessExportTwice();
+ test.createLayerOnBoot();
+ }
+}
diff --git a/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java b/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java
new file mode 100644
index 00000000000..5d1a690a740
--- /dev/null
+++ b/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * @test
+ * @summary Class p1.c1 in module first_mod cannot read p2.c2 in module second_mod,
+ * even after a read edge is added between first_mod and second_mod.
+ * Ensures constant access check answers when not accessible due to readability.
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.module
+ * @compile p2/c2.java
+ * @compile p1/c1.java
+ * @compile p4/c4.java
+ * @run main/othervm AccessReadTwice
+ */
+
+import static jdk.test.lib.Asserts.*;
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+//
+// ClassLoader1 --> defines first_mod --> packages p1, p4
+// defines second_mod --> package p2
+//
+// package p2 in second_mod is exported to first_mod
+//
+// class p1.c1 defined in first_mod tries to access p2.c2 defined in second_mod
+// Access is not allowed, even after a read edge is added between first_mod and second_mod.
+
+public class AccessReadTwice {
+
+ // Create a Layer over the boot layer.
+ // Define modules within this layer to test access between
+ // publicly defined classes within packages of those modules.
+ public void createLayerOnBoot() throws Throwable {
+
+ // Define module: first_mod
+ // Can read: java.base
+ // Packages: p1, p4
+ // Packages exported: none
+ ModuleDescriptor descriptor_first_mod =
+ ModuleDescriptor.module("first_mod")
+ .requires("java.base")
+ .contains(Set.of("p1", "p4"))
+ .build();
+
+ // Define module: second_mod
+ // Can read: java.base
+ // Packages: p2
+ // Packages exported: p2 is exported to first_mod
+ ModuleDescriptor descriptor_second_mod =
+ ModuleDescriptor.module("second_mod")
+ .requires("java.base")
+ .exports("p2", Set.of("first_mod"))
+ .build();
+
+ // Set up a ModuleFinder containing all modules for this layer
+ ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod);
+
+ // Resolves "first_mod" and "second_mod"
+ Configuration cf = Layer.boot()
+ .configuration()
+ .resolveRequires(finder, ModuleFinder.of(), Set.of("first_mod", "second_mod"));
+
+ // Map each module to this class loader
+ Map map = new HashMap<>();
+ ClassLoader loader = AccessReadTwice.class.getClassLoader();
+ map.put("first_mod", loader);
+ map.put("second_mod", loader);
+
+ // Create Layer that contains first_mod & second_mod
+ Layer layer = Layer.boot().defineModules(cf, map::get);
+
+ assertTrue(layer.findLoader("first_mod") == loader);
+ assertTrue(layer.findLoader("second_mod") == loader);
+ assertTrue(layer.findLoader("java.base") == null);
+
+ Class p2_c2_class = loader.loadClass("p2.c2");
+ Class p1_c1_class = loader.loadClass("p1.c1");
+ Class p4_c4_class = loader.loadClass("p4.c4");
+
+ Module first_mod = p1_c1_class.getModule();
+ Module second_mod = p2_c2_class.getModule();
+
+ // Export first_mod/p1 and first_mod/p4 to all unnamed modules so that
+ // this test can use them
+ jdk.internal.module.Modules.addExportsToAllUnnamed(first_mod, "p1");
+ jdk.internal.module.Modules.addExportsToAllUnnamed(first_mod, "p4");
+
+ // First access check for p1.c1
+ try {
+ p1_c1_class.newInstance();
+ throw new RuntimeException("Test Failed, module first_mod should not have access to p2.c2");
+ } catch (IllegalAccessError e) {
+ String message = e.getMessage();
+ if (!(message.contains("cannot access") &&
+ message.contains("because module first_mod does not read module second_mod"))) {
+ throw new RuntimeException("Wrong message: " + message);
+ } else {
+ System.out.println("Test Succeeded at attempt #1");
+ }
+ }
+
+ // Add a read edge from p4/c4's module (first_mod) to second_mod
+ p4.c4 c4_obj = new p4.c4();
+ c4_obj.addReads(second_mod);
+
+ // Second access check for p1.c1, should have same result as first
+ try {
+ p1_c1_class.newInstance();
+ throw new RuntimeException("Test Failed, access should have been cached above");
+ } catch (IllegalAccessError e) {
+ String message = e.getMessage();
+ if (!(message.contains("cannot access") &&
+ message.contains("because module first_mod does not read module second_mod"))) {
+ throw new RuntimeException("Wrong message: " + message);
+ } else {
+ System.out.println("Test Succeeded at attempt #2");
+ }
+ }
+ }
+
+ public static void main(String args[]) throws Throwable {
+ AccessReadTwice test = new AccessReadTwice();
+ test.createLayerOnBoot();
+ }
+}
diff --git a/hotspot/test/runtime/modules/AccessCheck/p4/c4.java b/hotspot/test/runtime/modules/AccessCheck/p4/c4.java
new file mode 100644
index 00000000000..d0098674672
--- /dev/null
+++ b/hotspot/test/runtime/modules/AccessCheck/p4/c4.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.
+ */
+
+// Small class used by multiple hotspot/runtime/modules/AccessCheck/* tests.
+
+package p4;
+
+import java.lang.reflect.Module;
+
+public class c4 {
+ // Add a read edge from c4's module to given module m
+ public void addReads(Module m) {
+ c4.class.getModule().addReads(m);
+ }
+}
diff --git a/hotspot/test/runtime/modules/JVMAddModulePackage.java b/hotspot/test/runtime/modules/JVMAddModulePackage.java
index 62106f8597f..3f7f2fd29a0 100644
--- a/hotspot/test/runtime/modules/JVMAddModulePackage.java
+++ b/hotspot/test/runtime/modules/JVMAddModulePackage.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -84,11 +84,11 @@ public class JVMAddModulePackage {
// Expected
}
- // Existing package, expect an IAE
+ // Existing package, expect an ISE
try {
ModuleHelper.AddModulePackage(module1, "yourpackage");
- throw new RuntimeException("Failed to get the expected IAE");
- } catch(IllegalArgumentException e) {
+ throw new RuntimeException("Failed to get the expected ISE");
+ } catch(IllegalStateException e) {
// Expected
}
diff --git a/hotspot/test/runtime/modules/JVMDefineModule.java b/hotspot/test/runtime/modules/JVMDefineModule.java
index dd19770ee98..9e44878490d 100644
--- a/hotspot/test/runtime/modules/JVMDefineModule.java
+++ b/hotspot/test/runtime/modules/JVMDefineModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -127,27 +127,27 @@ public class JVMDefineModule {
}
}
- // Duplicate module name, expect an IAE
- m = ModuleHelper.ModuleObject("module.name", cl, new String[] { "mypackage6" });
+ // Duplicate module name, expect an ISE
+ m = ModuleHelper.ModuleObject("Module_A", cl, new String[] { "mypackage6" });
assertNotNull(m, "Module should not be null");
ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6" });
try {
ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6a" });
- throw new RuntimeException("Failed to get IAE for duplicate module");
- } catch(IllegalArgumentException e) {
- if (!e.getMessage().contains("Module module.name is already defined")) {
- throw new RuntimeException("Failed to get expected IAE message for duplicate module: " + e.getMessage());
+ throw new RuntimeException("Failed to get ISE for duplicate module");
+ } catch(IllegalStateException e) {
+ if (!e.getMessage().contains("Module Module_A is already defined")) {
+ throw new RuntimeException("Failed to get expected ISE message for duplicate module: " + e.getMessage());
}
}
- // Package is already defined for class loader, expect an IAE
+ // Package is already defined for class loader, expect an ISE
m = ModuleHelper.ModuleObject("dupl.pkg.module", cl, new String[] { "mypackage6b" });
try {
ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6" });
- throw new RuntimeException("Failed to get IAE for existing package");
- } catch(IllegalArgumentException e) {
- if (!e.getMessage().contains("Package mypackage6 for module dupl.pkg.module already exists for class loader")) {
- throw new RuntimeException("Failed to get expected IAE message for duplicate package: " + e.getMessage());
+ throw new RuntimeException("Failed to get ISE for existing package");
+ } catch(IllegalStateException e) {
+ if (!e.getMessage().contains("Package mypackage6 for module dupl.pkg.module is already in another module, Module_A, defined to the class loader")) {
+ throw new RuntimeException("Failed to get expected ISE message for duplicate package: " + e.getMessage());
}
}
diff --git a/hotspot/test/serviceability/attach/AttachSetGetFlag.java b/hotspot/test/serviceability/attach/AttachSetGetFlag.java
index 3b48759cc23..2d6a28cfce3 100644
--- a/hotspot/test/serviceability/attach/AttachSetGetFlag.java
+++ b/hotspot/test/serviceability/attach/AttachSetGetFlag.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
* java.compiler
* java.management
* jdk.attach/sun.tools.attach
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run main AttachSetGetFlag
*/
diff --git a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java
index c22be26f951..8b3a8d8a47d 100644
--- a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java
+++ b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng/othervm -XX:+SegmentedCodeCache CodeCacheTest
* @run testng/othervm -XX:-SegmentedCodeCache CodeCacheTest
* @run testng/othervm -Xint -XX:+SegmentedCodeCache CodeCacheTest
diff --git a/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java b/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java
index e0bdd408012..11a28ec9a85 100644
--- a/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java
+++ b/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java
index c43dfafa56f..8d40423b5e8 100644
--- a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java
+++ b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java
@@ -49,7 +49,7 @@ public class CompilerDirectivesDCMDTest {
public void run(CommandExecutor executor) {
- if (Platform.isServer()) {
+ if (Platform.isServer() && !Platform.isEmulatedClient()) {
filename = System.getProperty("test.src", ".") + File.separator + "control2.txt";
} else {
filename = System.getProperty("test.src", ".") + File.separator + "control1.txt";
diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java
index 3640bbcebbb..a1b79533a3a 100644
--- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java
+++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @summary Test of diagnostic command Compiler.queue
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
diff --git a/hotspot/test/serviceability/dcmd/framework/HelpTest.java b/hotspot/test/serviceability/dcmd/framework/HelpTest.java
index b172db8e7ca..d88ddffce71 100644
--- a/hotspot/test/serviceability/dcmd/framework/HelpTest.java
+++ b/hotspot/test/serviceability/dcmd/framework/HelpTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@ import org.testng.annotations.Test;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng/othervm -XX:+UsePerfData HelpTest
*/
public class HelpTest {
diff --git a/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java b/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java
index be8a4d8560d..2536b4125aa 100644
--- a/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java
+++ b/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@ import org.testng.annotations.Test;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng/othervm -XX:+UsePerfData InvalidCommandTest
*/
public class InvalidCommandTest {
diff --git a/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java b/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java
index dadaf3113b2..d39f0de5263 100644
--- a/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java
+++ b/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@ import org.testng.annotations.Test;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng/othervm -XX:+UsePerfData VMVersionTest
*/
public class VMVersionTest {
diff --git a/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java b/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java
index bc2f3e2eb15..a3d244cef4e 100644
--- a/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java
+++ b/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng ClassHistogramAllTest
*/
public class ClassHistogramAllTest extends ClassHistogramTest {
diff --git a/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java b/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java
index 5b4f017ec40..fec990e5a10 100644
--- a/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java
+++ b/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@ import jdk.test.lib.dcmd.JMXExecutor;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng ClassHistogramTest
*/
public class ClassHistogramTest {
diff --git a/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java
index 257acea6b10..d811493c1d3 100644
--- a/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java
+++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng HeapDumpAllTest
*/
public class HeapDumpAllTest extends HeapDumpTest {
diff --git a/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java
index 257a30f899c..60444ae358c 100644
--- a/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java
+++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,7 +44,7 @@ import jdk.test.lib.dcmd.PidJcmdExecutor;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng HeapDumpTest
*/
public class HeapDumpTest {
diff --git a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java
index 22af05f0523..f49e4165688 100644
--- a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java
+++ b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@ import jdk.test.lib.process.ProcessTools;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build FinalizationRunner
* @run main RunFinalizationTest
*/
diff --git a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java
index 44bd09a6268..267e91381a5 100644
--- a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java
+++ b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@ import jdk.test.lib.dcmd.JMXExecutor;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng/othervm -Xlog:gc=debug:RunGC.gclog -XX:-ExplicitGCInvokesConcurrent RunGCTest
*/
public class RunGCTest {
diff --git a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java
index 373edf07857..c190353803f 100644
--- a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java
+++ b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java
@@ -41,7 +41,7 @@ import org.testng.annotations.Test;
* java.compiler
* java.instrument
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build SimpleJvmtiAgent
* @run main ClassFileInstaller SimpleJvmtiAgent
* @run testng LoadAgentDcmdTest
diff --git a/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java b/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java
index b931c42019e..c1ca3a35442 100644
--- a/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java
+++ b/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng PrintConcurrentLocksTest
*/
public class PrintConcurrentLocksTest extends PrintTest {
diff --git a/hotspot/test/serviceability/dcmd/thread/PrintTest.java b/hotspot/test/serviceability/dcmd/thread/PrintTest.java
index 77e22e1d8c5..e4af11c3261 100644
--- a/hotspot/test/serviceability/dcmd/thread/PrintTest.java
+++ b/hotspot/test/serviceability/dcmd/thread/PrintTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@ import java.util.regex.Pattern;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng PrintTest
*/
public class PrintTest {
diff --git a/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java b/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java
index aee55b5cc31..7c77a2d2a82 100644
--- a/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java
+++ b/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng ClassHierarchyTest
*/
diff --git a/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java b/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java
index d2230e33d8b..60f94069986 100644
--- a/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java
+++ b/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng ClassLoaderStatsTest
*/
diff --git a/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java b/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java
index ac04d02b382..72f009d75e4 100644
--- a/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java
+++ b/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@ import jdk.test.lib.dcmd.JMXExecutor;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis CommandLineTest
*/
public class CommandLineTest {
diff --git a/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java b/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java
index 3b4cfce1b60..4bda8a8f4c6 100644
--- a/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java
+++ b/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@ import jdk.test.lib.dcmd.JMXExecutor;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng DynLibsTest
*/
diff --git a/hotspot/test/serviceability/dcmd/vm/FlagsTest.java b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java
index f83ab760a49..3554a696119 100644
--- a/hotspot/test/serviceability/dcmd/vm/FlagsTest.java
+++ b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,7 @@ import org.testng.annotations.Test;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng/othervm -Xmx129m -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis_Right -XX:-TieredCompilation FlagsTest
*/
public class FlagsTest {
diff --git a/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java b/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java
index 71ec4e17139..8325dc85f39 100644
--- a/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java
+++ b/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@ import jdk.test.lib.dcmd.JMXExecutor;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng SystemPropertiesTest
*/
public class SystemPropertiesTest {
diff --git a/hotspot/test/serviceability/dcmd/vm/UptimeTest.java b/hotspot/test/serviceability/dcmd/vm/UptimeTest.java
index a907421d5da..77ff300ee2f 100644
--- a/hotspot/test/serviceability/dcmd/vm/UptimeTest.java
+++ b/hotspot/test/serviceability/dcmd/vm/UptimeTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,7 @@ import java.text.ParseException;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @run testng UptimeTest
*/
public class UptimeTest {
diff --git a/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java b/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java
index 1030675d8f3..0b30a67dd52 100644
--- a/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java
+++ b/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java
@@ -35,7 +35,7 @@ import jdk.test.lib.process.ProcessTools;
* java.compiler
* java.instrument
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build GetObjectSizeClassAgent
* @run main ClassFileInstaller GetObjectSizeClassAgent
* @run main GetObjectSizeClass
diff --git a/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java b/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java
index e2a801aaef8..57eabb72e8a 100644
--- a/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java
+++ b/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@ import jdk.test.lib.process.ProcessTools;
* java.compiler
* java.instrument
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build GetObjectSizeOverflowAgent
* @run main ClassFileInstaller GetObjectSizeOverflowAgent
* @run main GetObjectSizeOverflow
diff --git a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java
index 4a9bb2606fe..c6a203e86bc 100644
--- a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java
+++ b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
* java.instrument
* java.management
* jdk.jartool/sun.tools.jar
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build UnresolvedClassAgent
* @run main TestRedefineWithUnresolvedClass
*/
diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java
index c3dced229db..855fbad95c6 100644
--- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java
+++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java
@@ -21,12 +21,9 @@
* questions.
*/
-import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
+import jdk.test.lib.process.ProcessTools;
import sun.management.VMManagement;
@@ -38,7 +35,7 @@ public class JMapHProfLargeHeapProc {
buildLargeHeap(args);
// Print our pid on stdout
- System.out.println("PID[" + getProcessId() + "]");
+ System.out.println("PID[" + ProcessTools.getProcessId() + "]");
// Wait for input before termination
System.in.read();
@@ -50,22 +47,4 @@ public class JMapHProfLargeHeapProc {
}
}
- public static int getProcessId() throws Exception {
-
- // Get the current process id using a reflection hack
- RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
- Field jvm = runtime.getClass().getDeclaredField("jvm");
-
- jvm.setAccessible(true);
- VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
-
- Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId");
-
- pid_method.setAccessible(true);
-
- int pid = (Integer) pid_method.invoke(mgmt);
-
- return pid;
- }
-
}
diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java
index d2e64f75d34..2a46621d118 100644
--- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java
+++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,7 @@ import jdk.test.lib.process.ProcessTools;
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management/sun.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build JMapHProfLargeHeapProc
* @run main JMapHProfLargeHeapTest
*/
@@ -90,6 +90,9 @@ public class JMapHProfLargeHeapTest {
try (Scanner largeHeapScanner = new Scanner(
largeHeapProc.getInputStream());) {
String pidstring = null;
+ if (!largeHeapScanner.hasNext()) {
+ throw new RuntimeException ("Test failed: could not open largeHeapScanner.");
+ }
while ((pidstring = largeHeapScanner.findInLine("PID\\[[0-9].*\\]")) == null) {
Thread.sleep(500);
}
diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java
index 88a94f66cdf..98a3d29bfa4 100644
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java
@@ -59,6 +59,8 @@ public class CompileTheWorld {
OUT = os;
}
+ boolean passed = false;
+
try {
try {
if (ManagementFactory.getCompilationMXBean() == null) {
@@ -84,10 +86,10 @@ public class CompileTheWorld {
PathHandler.getClassCount(),
Compiler.getMethodCount(),
System.currentTimeMillis() - start);
+ passed = true;
} finally {
- if (os != null) {
- os.close();
- }
+ // might have started new threads
+ System.exit(passed ? 0 : 1);
}
}
diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java
index 4159c483408..75d82dd1ebd 100644
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java
@@ -101,10 +101,12 @@ public class Utils {
INITIAL_COMP_LEVEL = 1;
} else {
String vmName = System.getProperty("java.vm.name");
- if (Utils.endsWithIgnoreCase(vmName, " Server VM")) {
+ String vmInfo = System.getProperty("java.vm.info");
+ boolean isEmulatedClient = (vmInfo != null) && vmInfo.contains("emulated-client");
+ if (Utils.endsWithIgnoreCase(vmName, " Server VM") && !isEmulatedClient) {
INITIAL_COMP_LEVEL = 4;
} else if (Utils.endsWithIgnoreCase(vmName, " Client VM")
- || Utils.endsWithIgnoreCase(vmName, " Minimal VM")) {
+ || Utils.endsWithIgnoreCase(vmName, " Minimal VM") || isEmulatedClient) {
INITIAL_COMP_LEVEL = 1;
} else {
throw new RuntimeException("Unknown VM: " + vmName);
diff --git a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java
index 43c9715a95e..5e56d66bd4a 100644
--- a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java
+++ b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java
@@ -50,7 +50,7 @@ public class TestMutuallyExclusivePlatformPredicates {
OS("isAix", "isLinux", "isOSX", "isSolaris", "isWindows"),
VM_TYPE("isClient", "isServer", "isGraal", "isMinimal", "isZero", "isEmbedded"),
MODE("isInt", "isMixed", "isComp"),
- IGNORED("isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild",
+ IGNORED("isEmulatedClient", "isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild",
"shouldSAAttach", "canPtraceAttachLinux", "canAttachOSX",
"isTieredSupported");
diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java
index 31f24081fa1..e24461cdac9 100644
--- a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java
+++ b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java
@@ -30,11 +30,11 @@
* java.base/jdk.internal.reflect
* java.management
* @build sun.hotspot.WhiteBox Foo Bar
- * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
- * sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main ClassesDirTest prepare
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes
- * @run main ClassesDirTest check ctw.log
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run driver ClassesDirTest prepare
+ * @run driver ClassesDirTest compile classes
+ * @run driver ClassesDirTest check
* @summary testing of CompileTheWorld :: classes in directory
* @author igor.ignatyev@oracle.com
*/
diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java
index c2823de598c..5ffe27ba0c6 100644
--- a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java
+++ b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java
@@ -30,11 +30,11 @@
* java.base/jdk.internal.reflect
* java.management
* @build sun.hotspot.WhiteBox Foo Bar
- * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
- * sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main ClassesListTest prepare
- * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst
- * @run main ClassesListTest check ctw.log
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run driver ClassesListTest prepare
+ * @run driver/timeout=600 ClassesListTest compile classes.lst
+ * @run driver ClassesListTest check
* @summary testing of CompileTheWorld :: list of classes in file
* @author igor.ignatyev@oracle.com
*/
diff --git a/hotspot/test/testlibrary_tests/ctw/CtwTest.java b/hotspot/test/testlibrary_tests/ctw/CtwTest.java
index 06b16b631b9..eb6aedc1fbe 100644
--- a/hotspot/test/testlibrary_tests/ctw/CtwTest.java
+++ b/hotspot/test/testlibrary_tests/ctw/CtwTest.java
@@ -21,6 +21,7 @@
* questions.
*/
+import java.util.Arrays;
import java.util.List;
import java.util.Collections;
import java.util.ArrayList;
@@ -38,8 +39,20 @@ import java.nio.charset.Charset;
import jdk.test.lib.JDKToolFinder;
import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
public abstract class CtwTest {
+ private static final String LOG_FILE = "ctw.log";
+ private static final String[] CTW_COMMAND = {
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-Dsun.hotspot.tools.ctw.logfile=" + LOG_FILE,
+ "--add-exports", "java.base/jdk.internal.jimage=ALL-UNNAMED",
+ "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
+ "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
+ sun.hotspot.tools.ctw.CompileTheWorld.class.getName(),
+ };
protected final String[] shouldContain;
protected CtwTest(String[] shouldContain) {
this.shouldContain = shouldContain;
@@ -54,7 +67,10 @@ public abstract class CtwTest {
prepare();
break;
case "check":
- check(args);
+ check();
+ break;
+ case "compile":
+ compile(args);
break;
default:
throw new Error("unregonized action -- " + args[0]);
@@ -63,20 +79,27 @@ public abstract class CtwTest {
protected void prepare() throws Exception { }
- protected void check(String[] args) throws Exception {
- if (args.length < 2) {
- throw new Error("logfile isn't specified");
- }
- String logfile = args[1];
- try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile),
+ protected void check() throws Exception {
+ try (BufferedReader r = Files.newBufferedReader(Paths.get(LOG_FILE),
Charset.defaultCharset())) {
OutputAnalyzer output = readOutput(r);
- for (String test : shouldContain) {
+ for (String test : shouldContain) {
output.shouldContain(test);
}
}
}
+ protected void compile(String[] args) throws Exception {
+ // concat CTW_COMMAND and args w/o 0th element
+ String[] cmd = Arrays.copyOf(CTW_COMMAND, CTW_COMMAND.length + args.length - 1);
+ System.arraycopy(args, 1, cmd, CTW_COMMAND.length, args.length - 1);
+
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmd);
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ dump(output, "compile");
+ output.shouldHaveExitValue(0);
+ }
+
private static OutputAnalyzer readOutput(BufferedReader reader)
throws IOException {
StringBuilder builder = new StringBuilder();
diff --git a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java
index a784bda84ad..18ce6347b81 100644
--- a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java
+++ b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,13 +30,13 @@
* java.base/jdk.internal.reflect
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build sun.hotspot.WhiteBox Foo Bar
- * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
- * sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main JarDirTest prepare
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/*
- * @run main JarDirTest check ctw.log
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run driver JarDirTest prepare
+ * @run driver JarDirTest compile jars/*
+ * @run driver JarDirTest check
* @summary testing of CompileTheWorld :: jars in directory
* @author igor.ignatyev@oracle.com
*/
diff --git a/hotspot/test/testlibrary_tests/ctw/JarsTest.java b/hotspot/test/testlibrary_tests/ctw/JarsTest.java
index 16af1639854..cae3f7b7193 100644
--- a/hotspot/test/testlibrary_tests/ctw/JarsTest.java
+++ b/hotspot/test/testlibrary_tests/ctw/JarsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,13 +30,13 @@
* java.base/jdk.internal.reflect
* java.compiler
* java.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build sun.hotspot.WhiteBox Foo Bar
- * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
- * sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main JarsTest prepare
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar
- * @run main JarsTest check ctw.log
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run driver JarsTest prepare
+ * @run driver JarsTest compile foo.jar bar.jar
+ * @run driver JarsTest check
* @summary testing of CompileTheWorld :: jars
* @author igor.ignatyev@oracle.com
*/
diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java
index 302f77c3d31..79830375479 100644
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,7 +28,7 @@
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management/sun.management
- * jdk.jvmstat/sun.jvmstat.monitor
+ * jdk.internal.jvmstat/sun.jvmstat.monitor
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
diff --git a/jaxp/.hgtags b/jaxp/.hgtags
index 0fd6c10ce52..9804e10e82f 100644
--- a/jaxp/.hgtags
+++ b/jaxp/.hgtags
@@ -397,3 +397,4 @@ f85154af719f99a3b4d81b67a8b4c18a650d10f9 jdk-9+150
7e3da313b1746578da648155e37dd8526e83153d jdk-9+152
1384504d2cd0e55c5e0becaeaf40ab05cae959d6 jdk-9+153
7fa738305436d14c0926df0f04892890cacc766b jdk-9+154
+48fa77af153288b08ba794e1616a7b0685f3b67e jdk-9+155
diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java
index 2060a5ac8eb..32f79d67463 100644
--- a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java
+++ b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java
@@ -24,32 +24,32 @@
package transform;
import static jaxp.library.JAXPTestUtilities.getSystemProperty;
-import static jaxp.library.JAXPTestUtilities.tryRunWithTmpPermission;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.io.IOException;
-import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
import org.testng.Assert;
import org.testng.AssertJUnit;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
@@ -67,8 +67,7 @@ import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
-import com.sun.org.apache.xml.internal.serialize.OutputFormat;
-import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
+import transform.util.TransformerTestTemplate;
/*
* @test
@@ -91,250 +90,241 @@ public class TransformerTest {
private static final String NAMESPACE_PREFIXES =
"http://xml.org/sax/features/namespace-prefixes";
- private static abstract class TestTemplate {
- protected void printSnippet(String title, String snippet) {
- StringBuilder div = new StringBuilder();
- for (int i = 0; i < title.length(); i++)
- div.append("=");
- System.out.println(title + "\n" + div + "\n" + snippet + "\n");
- }
- }
+ public static class Test6272879 extends TransformerTestTemplate {
- /**
- * Reads the contents of the given file into a string.
- * WARNING: this method adds a final line feed even if the last line of the file doesn't contain one.
- *
- * @param f
- * The file to read
- * @return The content of the file as a string, with line terminators as \"n"
- * for all platforms
- * @throws IOException
- * If there was an error reading
- */
- private String getFileContentAsString(File f) throws IOException {
- try (BufferedReader reader = new BufferedReader(new FileReader(f))) {
- String line;
- StringBuilder sb = new StringBuilder();
- while ((line = reader.readLine()) != null) {
- sb.append(line).append("\n");
+ private static String XSL_INPUT =
+ "" + LINE_SEPARATOR +
+ "" + LINE_SEPARATOR +
+ "" + LINE_SEPARATOR +
+ "" + LINE_SEPARATOR +
+ "" + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ "" + LINE_SEPARATOR +
+ "" + LINE_SEPARATOR +
+ "";
+
+ private static String XML_INPUT =
+ "" + LINE_SEPARATOR +
+ // "" + LINE_SEPARATOR +
+ // "" + LINE_SEPARATOR +
+ // "" + LINE_SEPARATOR +
+ // "]>" +
+ // LINE_SEPARATOR +
+ "" + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " Valeur 1" + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ " Valeur 2" + LINE_SEPARATOR +
+ " " + LINE_SEPARATOR +
+ "";
+
+ public Test6272879() {
+ super(XSL_INPUT, XML_INPUT);
+ }
+
+ /*
+ * @bug 6272879
+ * @summary Test for JDK-6272879
+ * DomResult had truncated Strings in some places
+ */
+ @Test
+ public void run() throws TransformerException, ClassNotFoundException, InstantiationException,
+ IllegalAccessException, ClassCastException
+ {
+ // print input
+ printSnippet("Stylesheet:", getXsl());
+ printSnippet("Source before transformation:", getSourceXml());
+
+ // transform to DOM result
+ Transformer t = getTransformer();
+ DOMResult result = new DOMResult();
+ t.transform(getStreamSource(), result);
+
+ // print output
+ printSnippet("Result after transformation:", prettyPrintDOMResult(result));
+
+ // do some assertions
+ Document document = (Document)result.getNode();
+ NodeList nodes = document.getElementsByTagName("valeur2");
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+ AssertJUnit.assertEquals("Node value mismatch",
+ "Valeur " + (i + 1),
+ node.getFirstChild().getNodeValue());
+ AssertJUnit.assertEquals("Node attribute mismatch",
+ "Attribut " + (i + 1),
+ node.getAttributes().item(0).getNodeValue());
}
- return sb.toString();
}
}
- private class XMLReaderFor6305029 implements XMLReader {
- private boolean namespaces = true;
- private boolean namespacePrefixes = false;
- private EntityResolver resolver;
- private DTDHandler dtdHandler;
- private ContentHandler contentHandler;
- private ErrorHandler errorHandler;
+ public static class Test6305029 extends TransformerTestTemplate {
- public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
- if (name.equals(NAMESPACES)) {
- return namespaces;
- } else if (name.equals(NAMESPACE_PREFIXES)) {
- return namespacePrefixes;
- } else {
- throw new SAXNotRecognizedException();
+ private static String XML_INPUT =
+ "" + "";
+
+ // custom XMLReader representing XML_INPUT
+ private class MyXMLReader implements XMLReader {
+ private boolean namespaces = true;
+ private boolean namespacePrefixes = false;
+ private EntityResolver resolver;
+ private DTDHandler dtdHandler;
+ private ContentHandler contentHandler;
+ private ErrorHandler errorHandler;
+
+ public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+ if (name.equals(NAMESPACES)) {
+ return namespaces;
+ } else if (name.equals(NAMESPACE_PREFIXES)) {
+ return namespacePrefixes;
+ } else {
+ throw new SAXNotRecognizedException();
+ }
+ }
+
+ public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
+ if (name.equals(NAMESPACES)) {
+ namespaces = value;
+ } else if (name.equals(NAMESPACE_PREFIXES)) {
+ namespacePrefixes = value;
+ } else {
+ throw new SAXNotRecognizedException();
+ }
+ }
+
+ public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+ return null;
+ }
+
+ public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
+ }
+
+ public void setEntityResolver(final EntityResolver theResolver) {
+ this.resolver = theResolver;
+ }
+
+ public EntityResolver getEntityResolver() {
+ return resolver;
+ }
+
+ public void setDTDHandler(final DTDHandler theHandler) {
+ dtdHandler = theHandler;
+ }
+
+ public DTDHandler getDTDHandler() {
+ return dtdHandler;
+ }
+
+ public void setContentHandler(final ContentHandler handler) {
+ contentHandler = handler;
+ }
+
+ public ContentHandler getContentHandler() {
+ return contentHandler;
+ }
+
+ public void setErrorHandler(final ErrorHandler handler) {
+ errorHandler = handler;
+ }
+
+ public ErrorHandler getErrorHandler() {
+ return errorHandler;
+ }
+
+ public void parse(final InputSource input) throws IOException, SAXException {
+ parse();
+ }
+
+ public void parse(final String systemId) throws IOException, SAXException {
+ parse();
+ }
+
+ private void parse() throws SAXException {
+ contentHandler.startDocument();
+ contentHandler.startPrefixMapping("prefix", "namespaceUri");
+
+ AttributesImpl atts = new AttributesImpl();
+ if (namespacePrefixes) {
+ atts.addAttribute("", "xmlns:prefix", "xmlns:prefix", "CDATA", "namespaceUri");
+ }
+
+ contentHandler.startElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "", atts);
+ contentHandler.endElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "");
+ contentHandler.endPrefixMapping("prefix");
+ contentHandler.endDocument();
}
}
- public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
- if (name.equals(NAMESPACES)) {
- namespaces = value;
- } else if (name.equals(NAMESPACE_PREFIXES)) {
- namespacePrefixes = value;
- } else {
- throw new SAXNotRecognizedException();
- }
+ public Test6305029() {
+ super(null, XML_INPUT);
}
- public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
- return null;
- }
+ /*
+ * @bug 6305029
+ * @summary Test for JDK-6305029
+ * Test identity transformation
+ */
+ @Test
+ public void run() throws TransformerFactoryConfigurationError, TransformerException {
+ // get Identity transformer
+ Transformer t = getTransformer();
- public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
- }
+ // test SAXSource from custom XMLReader
+ SAXSource saxSource = new SAXSource(new MyXMLReader(), new InputSource());
+ StringWriter resultWriter = new StringWriter();
+ t.transform(saxSource, new StreamResult(resultWriter));
+ String resultString = resultWriter.toString();
+ printSnippet("Result after transformation from custom SAXSource:", resultString);
+ AssertJUnit.assertEquals("Identity transform of SAXSource", getSourceXml(), resultString);
- public void setEntityResolver(final EntityResolver theResolver) {
- this.resolver = theResolver;
- }
-
- public EntityResolver getEntityResolver() {
- return resolver;
- }
-
- public void setDTDHandler(final DTDHandler theHandler) {
- dtdHandler = theHandler;
- }
-
- public DTDHandler getDTDHandler() {
- return dtdHandler;
- }
-
- public void setContentHandler(final ContentHandler handler) {
- contentHandler = handler;
- }
-
- public ContentHandler getContentHandler() {
- return contentHandler;
- }
-
- public void setErrorHandler(final ErrorHandler handler) {
- errorHandler = handler;
- }
-
- public ErrorHandler getErrorHandler() {
- return errorHandler;
- }
-
- public void parse(final InputSource input) throws IOException, SAXException {
- parse();
- }
-
- public void parse(final String systemId) throws IOException, SAXException {
- parse();
- }
-
- private void parse() throws SAXException {
- contentHandler.startDocument();
- contentHandler.startPrefixMapping("prefix", "namespaceUri");
-
- AttributesImpl atts = new AttributesImpl();
- if (namespacePrefixes) {
- atts.addAttribute("", "xmlns:prefix", "xmlns:prefix", "CDATA", "namespaceUri");
- }
-
- contentHandler.startElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "", atts);
- contentHandler.endElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "");
- contentHandler.endPrefixMapping("prefix");
- contentHandler.endDocument();
+ // test StreamSource
+ printSnippet("Source before transformation of StreamSource:", getSourceXml());
+ resultWriter = new StringWriter();
+ t.transform(getStreamSource(), new StreamResult(resultWriter));
+ resultString = resultWriter.toString();
+ printSnippet("Result after transformation of StreamSource:", resultString);
+ AssertJUnit.assertEquals("Identity transform of StreamSource", getSourceXml(), resultString);
}
}
- /*
- * @bug 6272879
- * @summary Test for JDK-6272879
- */
- @Test
- public final void testBug6272879() throws Exception {
- final String xsl =
- "" + LINE_SEPARATOR +
- "" + LINE_SEPARATOR +
- "" + LINE_SEPARATOR +
- "" + LINE_SEPARATOR +
- "" + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- "" + LINE_SEPARATOR +
- "" + LINE_SEPARATOR +
- "";
+ public static class Test6505031 extends TransformerTestTemplate {
- final String sourceXml =
- "" + LINE_SEPARATOR +
- // "" + LINE_SEPARATOR +
- // "" + LINE_SEPARATOR +
- // "" + LINE_SEPARATOR +
- // "]>" +
- // LINE_SEPARATOR +
- "" + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " Valeur 1" + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- " Valeur 2" + LINE_SEPARATOR +
- " " + LINE_SEPARATOR +
- "";
+ public Test6505031() throws IOException {
+ super();
+ setXsl(fromInputStream(getClass().getResourceAsStream("transform.xsl")));
+ setSourceXml(fromInputStream(getClass().getResourceAsStream("template.xml")));
+ }
- System.out.println("Stylesheet:");
- System.out.println("=============================");
- System.out.println(xsl);
- System.out.println();
-
- System.out.println("Source before transformation:");
- System.out.println("=============================");
- System.out.println(sourceXml);
- System.out.println();
-
- // transform to DOM result
- TransformerFactory tf = TransformerFactory.newInstance();
- Transformer t = tf.newTransformer(new StreamSource(new ByteArrayInputStream(xsl.getBytes())));
- DOMResult result = new DOMResult();
- t.transform(new StreamSource(new ByteArrayInputStream(sourceXml.getBytes())), result);
- Document document = (Document)result.getNode();
-
- System.out.println("Result after transformation:");
- System.out.println("============================");
- tryRunWithTmpPermission(() -> {
- OutputFormat format = new OutputFormat();
- format.setIndenting(true);
- new XMLSerializer(System.out, format).serialize(document);
- }, new RuntimePermission("accessClassInPackage.com.sun.org.apache.xml.internal.serialize"));
- System.out.println();
-
- System.out.println("Node content for element valeur2:");
- System.out.println("=================================");
- NodeList nodes = document.getElementsByTagName("valeur2");
- for (int i = 0; i < nodes.getLength(); i++) {
- Node node = nodes.item(i);
- System.out.println(" Node value: " + node.getFirstChild().getNodeValue());
- System.out.println(" Node attribute: " + node.getAttributes().item(0).getNodeValue());
-
- AssertJUnit.assertEquals("Node value mismatch", "Valeur " + (i + 1), node.getFirstChild().getNodeValue());
- AssertJUnit.assertEquals("Node attribute mismatch", "Attribut " + (i + 1), node.getAttributes().item(0).getNodeValue());
+ /*
+ * @bug 6505031
+ * @summary Test transformer parses keys and their values coming from different xml documents.
+ */
+ @Test
+ public void run() throws TransformerFactoryConfigurationError, TransformerException {
+ Transformer t = getTransformer();
+ t.setParameter("config", getClass().getResource("config.xml").toString());
+ t.setParameter("mapsFile", getClass().getResource("maps.xml").toString());
+ StringWriter resultWriter = new StringWriter();
+ t.transform(getStreamSource(), new StreamResult(resultWriter));
+ String resultString = resultWriter.toString();
+ Assert.assertTrue(resultString.contains("map1key1value") && resultString.contains("map2key1value"));
}
}
- /*
- * @bug 6305029
- * @summary Test for JDK-6305029
- */
- @Test
- public final void testBug6305029() throws TransformerException {
- final String XML_DOCUMENT = "" + "";
+ public static class Test8169631 extends TransformerTestTemplate {
- // test SAXSource
- SAXSource saxSource = new SAXSource(new XMLReaderFor6305029(), new InputSource());
- StringWriter resultWriter = new StringWriter();
- TransformerFactory tf = TransformerFactory.newInstance();
- tf.newTransformer().transform(saxSource, new StreamResult(resultWriter));
- AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, resultWriter.toString());
-
- // test StreamSource
- StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT));
- resultWriter = new StringWriter();
- tf.newTransformer().transform(streamSource, new StreamResult(resultWriter));
- AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, resultWriter.toString());
- }
-
- /*
- * @bug 6505031
- * @summary Test transformer parses keys and their values coming from different xml documents.
- */
- @Test
- public final void testBug6505031() throws TransformerException {
- TransformerFactory tf = TransformerFactory.newInstance();
- Transformer t = tf.newTransformer(new StreamSource(getClass().getResource("transform.xsl").toString()));
- t.setParameter("config", getClass().getResource("config.xml").toString());
- t.setParameter("mapsFile", getClass().getResource("maps.xml").toString());
- StringWriter sw = new StringWriter();
- t.transform(new StreamSource(getClass().getResource("template.xml").toString()), new StreamResult(sw));
- String s = sw.toString();
- Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value"));
- }
-
- private static class Test8169631 extends TestTemplate {
- private final static String xsl =
+ private static String XSL_INPUT =
"" + LINE_SEPARATOR +
"" + LINE_SEPARATOR +
" " + LINE_SEPARATOR +
@@ -345,7 +335,7 @@ public class TransformerTest {
" " + LINE_SEPARATOR +
"" + LINE_SEPARATOR;
- private final static String sourceXml =
+ private static String XML_INPUT =
"" + LINE_SEPARATOR +
"" + LINE_SEPARATOR +
" 1" + LINE_SEPARATOR +
@@ -353,6 +343,10 @@ public class TransformerTest {
" 3" + LINE_SEPARATOR +
"" + LINE_SEPARATOR;
+ public Test8169631() {
+ super(XSL_INPUT, XML_INPUT);
+ }
+
/**
* Utility method to print out transformation result and check values.
*
@@ -380,103 +374,104 @@ public class TransformerTest {
type + " should have count of "+ attribCount + " attributes.");
}
- public void run() throws IOException, TransformerException,
- SAXException, ParserConfigurationException
+ @DataProvider(name = "testdata8169631")
+ public Object[][] testData()
+ throws TransformerConfigurationException, SAXException, IOException,
+ ParserConfigurationException, XMLStreamException
{
- printSnippet("Source:", sourceXml);
+ // get Transformers
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer t = getTransformer(tf);
+ Transformer tFromTemplates = getTemplates(tf).newTransformer();
- printSnippet("Stylesheet:", xsl);
-
- // create default transformer (namespace aware)
- TransformerFactory tf1 = TransformerFactory.newInstance();
- ByteArrayInputStream bais = new ByteArrayInputStream(xsl.getBytes());
- Transformer t1 = tf1.newTransformer(new StreamSource(bais));
-
- // test transformation from stream source with namespace support
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- bais = new ByteArrayInputStream(sourceXml.getBytes());
- t1.transform(new StreamSource(bais), new StreamResult(baos));
- verifyResult("StreamSource with namespace support", baos.toString(), 0, 1);
-
- // test transformation from DOM source with namespace support
- bais.reset();
- baos.reset();
+ // get DOMSource objects
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DOMSource domSourceWithoutNS = getDOMSource(dbf);
dbf.setNamespaceAware(true);
- Document doc = dbf.newDocumentBuilder().parse(new InputSource(bais));
- t1.transform(new DOMSource(doc), new StreamResult(baos));
- verifyResult("DOMSource with namespace support", baos.toString(), 0, 1);
+ DOMSource domSourceWithNS = getDOMSource(dbf);
- // test transformation from DOM source without namespace support
- bais.reset();
- baos.reset();
- dbf.setNamespaceAware(false);
- doc = dbf.newDocumentBuilder().parse(new InputSource(bais));
- t1.transform(new DOMSource(doc), new StreamResult(baos));
- verifyResult("DOMSource without namespace support", baos.toString(), 3, 3);
-
- // test transformation from SAX source with namespace support
- bais.reset();
- baos.reset();
+ // get SAXSource objects
SAXParserFactory spf = SAXParserFactory.newInstance();
+ SAXSource saxSourceWithoutNS = getSAXSource(spf);
spf.setNamespaceAware(true);
- XMLReader xmlr = spf.newSAXParser().getXMLReader();
- SAXSource saxS = new SAXSource(xmlr, new InputSource(bais));
- t1.transform(saxS, new StreamResult(baos));
- verifyResult("SAXSource with namespace support", baos.toString(), 0, 1);
+ SAXSource saxSourceWithNS = getSAXSource(spf);
- // test transformation from SAX source without namespace support
- bais.reset();
- baos.reset();
- spf.setNamespaceAware(false);
- xmlr = spf.newSAXParser().getXMLReader();
- saxS = new SAXSource(xmlr, new InputSource(bais));
- t1.transform(saxS, new StreamResult(baos));
- verifyResult("SAXSource without namespace support", baos.toString(), 3, 3);
+ // get StAXSource objects
+ XMLInputFactory xif = XMLInputFactory.newInstance();
+ StAXSource staxSourceWithNS = getStAXSource(xif);
+
+ // print XML/XSL snippets to ease understanding of result
+ printSnippet("Source:", getSourceXml());
+ printSnippet("Stylesheet:", getXsl());
+
+ return new Object[][] {
+ // test StreamSource input with all transformers
+ // namespace awareness is set by transformer
+ {t, getStreamSource(), "StreamSource with namespace support", 0, 1},
+ {tFromTemplates, getStreamSource(), "StreamSource with namespace support using templates", 0, 1},
+ // now test DOMSource, SAXSource and StAXSource
+ // with rotating use of created transformers
+ // namespace awareness is set by source objects
+ {t, domSourceWithNS, "DOMSource with namespace support", 0, 1},
+ {t, domSourceWithoutNS, "DOMSource without namespace support", 3, 3},
+ {tFromTemplates, saxSourceWithNS, "SAXSource with namespace support", 0, 1},
+ {tFromTemplates, saxSourceWithoutNS, "SAXSource without namespace support", 3, 3},
+ {t, staxSourceWithNS, "StAXSource with namespace support", 0, 1}
+ };
+ }
+
+ /*
+ * @bug 8169631
+ * @summary Test combinations of namespace awareness settings on
+ * XSL transformations
+ */
+ @Test(dataProvider = "testdata8169631")
+ public void run(Transformer t, Source s, String label, int elementcount, int attributecount)
+ throws TransformerException
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ t.transform(s, new StreamResult(baos));
+ verifyResult(label, baos.toString(), elementcount, attributecount);
}
}
- /*
- * @bug 8169631
- * @summary Test combinations of namespace awareness settings on
- * XSL transformations
- */
- @Test
- public final void testBug8169631() throws IOException, SAXException,
- TransformerException, ParserConfigurationException
- {
- new Test8169631().run();
+ public static class Test8150704 extends TransformerTestTemplate {
+
+ public Test8150704() {
+ super();
+ }
+
+ @DataProvider(name = "testdata8150704")
+ public Object[][] testData() {
+ return new Object[][] {
+ {"Bug8150704-1.xsl", "Bug8150704-1.xml", "Bug8150704-1.ref"},
+ {"Bug8150704-2.xsl", "Bug8150704-2.xml", "Bug8150704-2.ref"}
+ };
+ }
+
+ /*
+ * @bug 8150704
+ * @summary Test that XSL transformation with lots of temporary result
+ * trees will not run out of DTM IDs.
+ */
+ @Test(dataProvider = "testdata8150704")
+ public void run(String xsl, String xml, String ref) throws IOException, TransformerException {
+ System.out.println("Testing transformation of " + xml + "...");
+ setXsl(fromInputStream(getClass().getResourceAsStream(xsl)));
+ setSourceXml(fromInputStream(getClass().getResourceAsStream(xml)));
+ Transformer t = getTransformer();
+ StringWriter resultWriter = new StringWriter();
+ t.transform(getStreamSource(), new StreamResult(resultWriter));
+ String resultString = resultWriter.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n").trim();
+ String reference = fromInputStream(getClass().getResourceAsStream(ref)).trim();
+ Assert.assertEquals(resultString, reference, "Output of transformation of " + xml + " does not match reference");
+ System.out.println("Passed.");
+ }
}
- /*
- * @bug 8150704
- * @summary Test that XSL transformation with lots of temporary result
- * trees will not run out of DTM IDs.
- */
- @Test
- public final void testBug8150704() throws TransformerException, IOException {
- System.out.println("Testing transformation of Bug8150704-1.xml...");
- TransformerFactory tf = TransformerFactory.newInstance();
- Transformer t = tf.newTransformer(new StreamSource(getClass().getResource("Bug8150704-1.xsl").toString()));
- StringWriter sw = new StringWriter();
- t.transform(new StreamSource(getClass().getResource("Bug8150704-1.xml").toString()), new StreamResult(sw));
- String resultstring = sw.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n");
- String reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-1.ref").getPath()));
- Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-1.xml does not match reference");
- System.out.println("Passed.");
+ public static class Test8162598 extends TransformerTestTemplate {
- System.out.println("Testing transformation of Bug8150704-2.xml...");
- t = tf.newTransformer(new StreamSource(getClass().getResource("Bug8150704-2.xsl").toString()));
- sw = new StringWriter();
- t.transform(new StreamSource(getClass().getResource("Bug8150704-2.xml").toString()), new StreamResult(sw));
- resultstring = sw.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n");
- reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-2.ref").getPath()));
- Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-2.xml does not match reference");
- System.out.println("Passed.");
- }
-
- private static class Test8162598 extends TestTemplate {
- private static final String xsl =
+ private static String XSL_INPUT =
"" + LINE_SEPARATOR +
"" + LINE_SEPARATOR +
" " + LINE_SEPARATOR +
@@ -494,8 +489,13 @@ public class TransformerTest {
" " + LINE_SEPARATOR +
"";
- private static final String sourceXml =
+ private static String XML_INPUT =
"" + LINE_SEPARATOR;
+
+ public Test8162598() {
+ super(XSL_INPUT, XML_INPUT);
+ }
+
/**
* Utility method for testBug8162598().
* Provides a convenient way to check/assert the expected namespaces
@@ -510,7 +510,6 @@ public class TransformerTest {
* @param nsc
* Expected namespace of the first sibling of the first sibling
*/
-
private void checkNodeNS(Node test, String nstest, String nsb, String nsc) {
String testNodeName = test.getNodeName();
if (nstest == null) {
@@ -532,29 +531,27 @@ public class TransformerTest {
}
}
+ /*
+ * @bug 8162598
+ * @summary Test XSLTC handling of namespaces, especially empty namespace
+ * definitions to reset the default namespace
+ */
+ @Test
public void run() throws Exception {
- printSnippet("Source:", sourceXml);
-
- printSnippet("Stylesheet:", xsl);
+ // print input
+ printSnippet("Source:", getSourceXml());
+ printSnippet("Stylesheet:", getXsl());
// transform to DOM result
- TransformerFactory tf = TransformerFactory.newInstance();
- ByteArrayInputStream bais = new ByteArrayInputStream(xsl.getBytes());
- Transformer t = tf.newTransformer(new StreamSource(bais));
+ Transformer t = getTransformer();
DOMResult result = new DOMResult();
- bais = new ByteArrayInputStream(sourceXml.getBytes());
- t.transform(new StreamSource(bais), result);
+ t.transform(getStreamSource(), result);
+
+ // print output
+ printSnippet("Result after transformation:", prettyPrintDOMResult(result));
+
+ // do some verifications
Document document = (Document)result.getNode();
-
- System.out.println("Result after transformation:");
- System.out.println("============================");
- tryRunWithTmpPermission(() -> {
- OutputFormat format = new OutputFormat();
- format.setIndenting(true);
- new XMLSerializer(System.out, format).serialize(document);
- }, new RuntimePermission("accessClassInPackage.com.sun.org.apache.xml.internal.serialize"));
- System.out.println();
-
checkNodeNS(document.getElementsByTagName("test1").item(0), "ns2", "ns2", null);
checkNodeNS(document.getElementsByTagName("test2").item(0), "ns1", "ns2", null);
checkNodeNS(document.getElementsByTagName("test3").item(0), null, null, null);
@@ -565,68 +562,74 @@ public class TransformerTest {
}
}
- /*
- * @bug 8162598
- * @summary Test XSLTC handling of namespaces, especially empty namespace
- * definitions to reset the default namespace
- */
- @Test
- public final void testBug8162598() throws Exception {
- new Test8162598().run();
+ public static class Test8169112 extends TransformerTestTemplate{
+
+ public static String XML_INPUT =
+ "";
+
+ public Test8169112() throws IOException {
+ super();
+ setXsl(fromInputStream(getClass().getResourceAsStream("Bug8169112.xsl")));
+ setSourceXml(XML_INPUT);
+ }
+
+ /**
+ * @throws TransformerException
+ * @bug 8169112
+ * @summary Test compilation of large xsl file with outlining.
+ *
+ * This test merely compiles a large xsl file and tests if its bytecode
+ * passes verification by invoking the transform() method for
+ * dummy content. The test succeeds if no Exception is thrown
+ */
+ @Test
+ public void run() throws TransformerException {
+ Transformer t = getTransformer();
+ t.transform(getStreamSource(), new StreamResult(new ByteArrayOutputStream()));
+ }
}
- /**
- * @bug 8169112
- * @summary Test compilation of large xsl file with outlining.
- *
- * This test merely compiles a large xsl file and tests if its bytecode
- * passes verification by invoking the transform() method for
- * dummy content. The test succeeds if no Exception is thrown
- */
- @Test
- public final void testBug8169112() throws FileNotFoundException,
- TransformerException
- {
- TransformerFactory tf = TransformerFactory.newInstance();
- String xslFile = getClass().getResource("Bug8169112.xsl").toString();
- Transformer t = tf.newTransformer(new StreamSource(xslFile));
- String xmlIn = "";
- ByteArrayInputStream bis = new ByteArrayInputStream(xmlIn.getBytes());
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- t.transform(new StreamSource(bis), new StreamResult(bos));
- }
+ public static class Test8169772 extends TransformerTestTemplate {
- /**
- * @bug 8169772
- * @summary Test transformation of DOM with null valued text node
- *
- * This test would throw a NullPointerException during transform when the
- * fix was not present.
- */
- @Test
- public final void testBug8169772() throws ParserConfigurationException,
- SAXException, IOException, TransformerException
- {
- // create a small DOM
- Document doc = DocumentBuilderFactory.newInstance().
- newDocumentBuilder().parse(
- new ByteArrayInputStream(
- "".getBytes()
- )
- );
+ public Test8169772() {
+ super();
+ }
- // insert a bad element
- Element e = doc.createElement("ERROR");
- e.appendChild(doc.createTextNode(null));
- doc.getDocumentElement().appendChild(e);
+ private Document getDOMWithBadElement() throws SAXException, IOException, ParserConfigurationException {
+ // create a small DOM
+ Document doc = DocumentBuilderFactory.newInstance().
+ newDocumentBuilder().parse(
+ new ByteArrayInputStream(
+ "".getBytes()
+ )
+ );
- // transform
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- TransformerFactory.newInstance().newTransformer().transform(
- new DOMSource(doc.getDocumentElement()), new StreamResult(bos)
- );
- System.out.println("Transformation result (DOM with null text node):");
- System.out.println("================================================");
- System.out.println(bos);
+ // insert a bad element
+ Element e = doc.createElement("ERROR");
+ e.appendChild(doc.createTextNode(null));
+ doc.getDocumentElement().appendChild(e);
+
+ return doc;
+ }
+
+ /**
+ * @throws ParserConfigurationException
+ * @throws IOException
+ * @throws SAXException
+ * @throws TransformerException
+ * @bug 8169772
+ * @summary Test transformation of DOM with null valued text node
+ *
+ * This test would throw a NullPointerException during transform when the
+ * fix was not present.
+ */
+ @Test
+ public void run() throws SAXException, IOException, ParserConfigurationException, TransformerException {
+ Transformer t = getTransformer();
+ StringWriter resultWriter = new StringWriter();
+ DOMSource d = new DOMSource(getDOMWithBadElement().getDocumentElement());
+ t.transform(d, new StreamResult(resultWriter));
+ printSnippet("Transformation result (DOM with null text node):", resultWriter.toString());
+ }
}
}
diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/util/TransformerTestTemplate.java b/jaxp/test/javax/xml/jaxp/unittest/transform/util/TransformerTestTemplate.java
new file mode 100644
index 00000000000..a102a21f4e2
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/transform/util/TransformerTestTemplate.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package transform.util;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.stream.Collectors;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.bootstrap.DOMImplementationRegistry;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSSerializer;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/*
+ * Template for Transformer tests
+ */
+public abstract class TransformerTestTemplate {
+ private String xsl = null;
+ private String sourceXml = null;
+
+ public TransformerTestTemplate() {
+ super();
+ }
+
+ public TransformerTestTemplate(String xsl, String sourceXml) {
+ super();
+ this.xsl = xsl;
+ this.sourceXml = sourceXml;
+ }
+
+ public String getXsl() {
+ return xsl;
+ }
+
+ public void setXsl(String xsl) {
+ this.xsl = xsl;
+ }
+
+ public String getSourceXml() {
+ return sourceXml;
+ }
+
+ public void setSourceXml(String sourceXml) {
+ this.sourceXml = sourceXml;
+ }
+
+ public String fromInputStream(InputStream is) throws IOException {
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
+ return br.lines().collect(Collectors.joining("\n"));
+ }
+ }
+
+ // print an XML Snippet under a given title
+ public void printSnippet(String title, String snippet) {
+ StringBuilder div = new StringBuilder();
+ for (int i = 0; i < title.length(); i++)
+ div.append("=");
+ System.out.println(title + "\n" + div + "\n" + snippet + "\n");
+ }
+
+ // pretty print a DOMResult
+ public String prettyPrintDOMResult(DOMResult dr) throws ClassNotFoundException, InstantiationException,
+ IllegalAccessException, ClassCastException
+ {
+ DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
+ DOMImplementationLS domImplementationLS = (DOMImplementationLS)registry.getDOMImplementation("LS");
+ StringWriter writer = new StringWriter();
+ LSOutput formattedOutput = domImplementationLS.createLSOutput();
+ formattedOutput.setCharacterStream(writer);
+ LSSerializer domSerializer = domImplementationLS.createLSSerializer();
+ domSerializer.getDomConfig().setParameter("format-pretty-print", true);
+ domSerializer.getDomConfig().setParameter("xml-declaration", false);
+ domSerializer.write(dr.getNode(), formattedOutput);
+ return writer.toString();
+ }
+
+ public Transformer getTransformer() throws TransformerConfigurationException {
+ return getTransformer(null);
+ }
+
+ // utility to obtain Transformer from TransformerFactory
+ public Transformer getTransformer(TransformerFactory tf)
+ throws TransformerConfigurationException
+ {
+ if (tf == null) {
+ tf = TransformerFactory.newInstance();
+ }
+
+ if (xsl == null) {
+ return tf.newTransformer();
+ } else {
+ return tf.newTransformer(
+ new StreamSource(new ByteArrayInputStream(xsl.getBytes()))
+ );
+ }
+ }
+
+ // utility to obtain Templates from TransformerFactory
+ public Templates getTemplates(TransformerFactory tf)
+ throws TransformerConfigurationException
+ {
+ return tf.newTemplates(
+ new StreamSource(new ByteArrayInputStream(xsl.getBytes()))
+ );
+ }
+
+ // utility to construct StreamSource
+ public StreamSource getStreamSource() {
+ return new StreamSource(
+ new ByteArrayInputStream(sourceXml.getBytes())
+ );
+ }
+
+ // utility to construct DOMSource from DocumentBuilderFactory
+ public DOMSource getDOMSource(DocumentBuilderFactory dbf)
+ throws SAXException, IOException, ParserConfigurationException
+ {
+ return new DOMSource(
+ dbf.newDocumentBuilder().parse(
+ new InputSource(
+ new ByteArrayInputStream(sourceXml.getBytes())
+ )
+ )
+ );
+ }
+
+ // utility to construct SAXSource from SAXParserFactory
+ public SAXSource getSAXSource(SAXParserFactory spf)
+ throws SAXException, ParserConfigurationException
+ {
+ return new SAXSource(
+ spf.newSAXParser().getXMLReader(),
+ new InputSource(new ByteArrayInputStream(sourceXml.getBytes()))
+ );
+ }
+
+ // utility to construct StAXSource from XMLInputFactory
+ public StAXSource getStAXSource(XMLInputFactory xif)
+ throws XMLStreamException
+ {
+ return new StAXSource(
+ xif.createXMLStreamReader(new StringReader(sourceXml))
+ );
+ }
+}
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index fd2f5b815b4..b130a70170d 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -400,3 +400,4 @@ c48b4d4768b1c2b8fe5d1a844ca13732e5dfbe2a jdk-9+151
6f8fb1cf7e5f61c40dcc3654f9a623c505f6de1f jdk-9+152
7a532a9a227137155b905341d4b99939db51220e jdk-9+153
34af95c7dbff74f3448fcdb7d745524e8a1cc88a jdk-9+154
+9b9918656c97724fd89c04a8547043bbd37f5935 jdk-9+155
diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/Generated.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Generated.java
similarity index 100%
rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/Generated.java
rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Generated.java
diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/PostConstruct.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/PostConstruct.java
similarity index 100%
rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/PostConstruct.java
rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/PostConstruct.java
diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/PreDestroy.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/PreDestroy.java
similarity index 100%
rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/PreDestroy.java
rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/PreDestroy.java
diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/Resource.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Resource.java
similarity index 100%
rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/Resource.java
rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Resource.java
diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/Resources.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Resources.java
similarity index 100%
rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/Resources.java
rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Resources.java
diff --git a/jaxws/src/java.annotations.common/share/classes/module-info.java b/jaxws/src/java.xml.ws.annotation/share/classes/module-info.java
similarity index 91%
rename from jaxws/src/java.annotations.common/share/classes/module-info.java
rename to jaxws/src/java.xml.ws.annotation/share/classes/module-info.java
index fddb78c5efc..58a625918fe 100644
--- a/jaxws/src/java.annotations.common/share/classes/module-info.java
+++ b/jaxws/src/java.xml.ws.annotation/share/classes/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@
* Defines a subset of the Common Annotations API to support programs running
* on the Java SE Platform.
*/
-module java.annotations.common {
+module java.xml.ws.annotation {
exports javax.annotation;
}
diff --git a/jaxws/src/java.xml.ws/share/classes/module-info.java b/jaxws/src/java.xml.ws/share/classes/module-info.java
index def2ec6be19..4a0175eeae2 100644
--- a/jaxws/src/java.xml.ws/share/classes/module-info.java
+++ b/jaxws/src/java.xml.ws/share/classes/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@ module java.xml.ws {
requires transitive java.activation;
requires transitive java.xml;
requires transitive java.xml.bind;
- requires java.annotations.common;
+ requires java.xml.ws.annotation;
requires java.desktop;
requires java.logging;
requires java.management;
diff --git a/jdk/.hgtags b/jdk/.hgtags
index 5a7c6ba2850..e6379a2ee4f 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -398,3 +398,4 @@ a20f2cf90762673e1bc4980fd6597e70a2578045 jdk-9+152
1c4411322327aea3f91011ec3977a12a05b09629 jdk-9+153
c97e7a8b8da062b9070df442f9cf308e10845fb7 jdk-9+154
e170c858888e83d5c0994504599b6ed7a1fb0cfc jdk-9+155
+7d64e541a6c04c714bcad4c8b553db912f827cd5 jdk-9+156
diff --git a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java
index 4de7b5c719a..ac1f9b86090 100644
--- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java
+++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java
@@ -153,9 +153,9 @@ public class GenGraphs {
*/
void genDotFile(String name, Set roots) throws IOException {
Configuration cf =
- Configuration.empty().resolveRequires(ModuleFinder.ofSystem(),
- ModuleFinder.of(),
- roots);
+ Configuration.empty().resolve(ModuleFinder.ofSystem(),
+ ModuleFinder.of(),
+ roots);
Set mds = cf.modules().stream()
.map(ResolvedModule::reference)
diff --git a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java
index e55a1c04855..520fb1b96b0 100644
--- a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java
+++ b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java
@@ -291,9 +291,9 @@ public class ModuleSummary {
static Configuration resolve(Set roots) {
return Configuration.empty()
- .resolveRequires(ModuleFinder.ofSystem(),
- ModuleFinder.of(),
- roots);
+ .resolve(ModuleFinder.ofSystem(),
+ ModuleFinder.of(),
+ roots);
}
static class HtmlDocument {
diff --git a/jdk/src/java.base/aix/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/aix/classes/sun/nio/fs/DefaultFileSystemProvider.java
new file mode 100644
index 00000000000..8c33d7e5a59
--- /dev/null
+++ b/jdk/src/java.base/aix/classes/sun/nio/fs/DefaultFileSystemProvider.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.spi.FileSystemProvider;
+
+/**
+ * Creates this platform's default FileSystemProvider.
+ */
+
+public class DefaultFileSystemProvider {
+ private DefaultFileSystemProvider() { }
+
+ /**
+ * Returns the default FileSystemProvider.
+ */
+ public static FileSystemProvider create() {
+ return new AixFileSystemProvider();
+ }
+}
diff --git a/jdk/src/java.base/linux/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/linux/classes/sun/nio/fs/DefaultFileSystemProvider.java
new file mode 100644
index 00000000000..82a06b7ea50
--- /dev/null
+++ b/jdk/src/java.base/linux/classes/sun/nio/fs/DefaultFileSystemProvider.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.spi.FileSystemProvider;
+
+/**
+ * Creates this platform's default FileSystemProvider.
+ */
+
+public class DefaultFileSystemProvider {
+ private DefaultFileSystemProvider() { }
+
+ /**
+ * Returns the default FileSystemProvider.
+ */
+ public static FileSystemProvider create() {
+ return new LinuxFileSystemProvider();
+ }
+}
diff --git a/jdk/src/java.base/macosx/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/macosx/classes/sun/nio/fs/DefaultFileSystemProvider.java
new file mode 100644
index 00000000000..917d9f3a25b
--- /dev/null
+++ b/jdk/src/java.base/macosx/classes/sun/nio/fs/DefaultFileSystemProvider.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.spi.FileSystemProvider;
+
+/**
+ * Creates this platform's default FileSystemProvider.
+ */
+
+public class DefaultFileSystemProvider {
+ private DefaultFileSystemProvider() { }
+
+ /**
+ * Returns the default FileSystemProvider.
+ */
+ public static FileSystemProvider create() {
+ return new MacOSXFileSystemProvider();
+ }
+}
diff --git a/jdk/src/java.base/share/classes/java/lang/Class.java b/jdk/src/java.base/share/classes/java/lang/Class.java
index b0e3d3af0cd..0a3b1da91a1 100644
--- a/jdk/src/java.base/share/classes/java/lang/Class.java
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java
@@ -425,6 +425,7 @@ public final class Class implements java.io.Serializable,
*
*
* @since 9
+ * @spec JPMS
*/
@CallerSensitive
public static Class> forName(Module module, String name) {
@@ -819,6 +820,7 @@ public final class Class implements java.io.Serializable,
* @return the module that this class or interface is a member of
*
* @since 9
+ * @spec JPMS
*/
public Module getModule() {
return module;
@@ -924,6 +926,8 @@ public final class Class implements java.io.Serializable,
* this method returns {@code null}.
*
* @return the package of this class.
+ * @revised 9
+ * @spec JPMS
*/
public Package getPackage() {
if (isPrimitive() || isArray()) {
@@ -951,20 +955,30 @@ public final class Class implements java.io.Serializable,
* declaring class} of the {@link #getEnclosingMethod enclosing method} or
* {@link #getEnclosingConstructor enclosing constructor}.
*
- *
This method returns {@code null} if this class represents an array type,
- * a primitive type or void.
+ *
If this class represents an array type then this method returns the
+ * package name of the element type. If this class represents a primitive
+ * type or void then the package name "{@code java.lang}" is returned.
*
* @return the fully qualified package name
*
* @since 9
+ * @spec JPMS
* @jls 6.7 Fully Qualified Names
*/
public String getPackageName() {
String pn = this.packageName;
- if (pn == null && !isArray() && !isPrimitive()) {
- String cn = getName();
- int dot = cn.lastIndexOf('.');
- pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
+ if (pn == null) {
+ Class> c = this;
+ while (c.isArray()) {
+ c = c.getComponentType();
+ }
+ if (c.isPrimitive()) {
+ pn = "java.lang";
+ } else {
+ String cn = c.getName();
+ int dot = cn.lastIndexOf('.');
+ pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
+ }
this.packageName = pn;
}
return pn;
@@ -2491,10 +2505,16 @@ public final class Class implements java.io.Serializable,
* Finds a resource with a given name.
*
*
If this class is in a named {@link Module Module} then this method
- * will attempt to find the resource in the module by means of the absolute
- * resource name, subject to the rules for encapsulation specified in the
- * {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
- * method.
+ * will attempt to find the resource in the module. This is done by
+ * delegating to the module's class loader {@link
+ * ClassLoader#findResource(String,String) findResource(String,String)}
+ * method, invoking it with the module name and the absolute name of the
+ * resource. Resources in named modules are subject to the rules for
+ * encapsulation specified in the {@code Module} {@link
+ * Module#getResourceAsStream getResourceAsStream} method and so this
+ * method returns {@code null} when the resource is a
+ * non-"{@code .class}" resource in a package that is not open to the
+ * caller's module.
*
*
Otherwise, if this class is not in a named module then the rules for
* searching resources associated with a given class are implemented by the
@@ -2503,9 +2523,8 @@ public final class Class implements java.io.Serializable,
* the bootstrap class loader, the method delegates to {@link
* ClassLoader#getSystemResourceAsStream}.
*
- *
Before finding a resource in the caller's module or delegation to a
- * class loader, an absolute resource name is constructed from the given
- * resource name using this algorithm:
+ *
Before delegation, an absolute resource name is constructed from the
+ * given resource name using this algorithm:
*
*
*
@@ -2532,7 +2551,11 @@ public final class Class implements java.io.Serializable,
* least the caller module, or access to the resource is denied
* by the security manager.
* @throws NullPointerException If {@code name} is {@code null}
+ *
+ * @see Module#getResourceAsStream(String)
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public InputStream getResourceAsStream(String name) {
@@ -2585,10 +2608,16 @@ public final class Class implements java.io.Serializable,
* Finds a resource with a given name.
*
*
If this class is in a named {@link Module Module} then this method
- * will attempt to find the resource in the module by means of the absolute
- * resource name, subject to the rules for encapsulation specified in the
- * {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
- * method.
+ * will attempt to find the resource in the module. This is done by
+ * delegating to the module's class loader {@link
+ * ClassLoader#findResource(String,String) findResource(String,String)}
+ * method, invoking it with the module name and the absolute name of the
+ * resource. Resources in named modules are subject to the rules for
+ * encapsulation specified in the {@code Module} {@link
+ * Module#getResourceAsStream getResourceAsStream} method and so this
+ * method returns {@code null} when the resource is a
+ * non-"{@code .class}" resource in a package that is not open to the
+ * caller's module.
*
*
Otherwise, if this class is not in a named module then the rules for
* searching resources associated with a given class are implemented by the
@@ -2627,6 +2656,8 @@ public final class Class implements java.io.Serializable,
* manager.
* @throws NullPointerException If {@code name} is {@code null}
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public URL getResource(String name) {
diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java
index fb771c29a10..06da4a983e1 100644
--- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java
+++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java
@@ -207,6 +207,8 @@ import sun.security.util.SecurityConstants;
* @jls 13.1 The Form of a Binary
* @see #resolveClass(Class)
* @since 1.0
+ * @revised 9
+ * @spec JPMS
*/
public abstract class ClassLoader {
@@ -380,12 +382,12 @@ public abstract class ClassLoader {
* method doesn't allow creation of a new class loader.
*
* @since 9
+ * @spec JPMS
*/
protected ClassLoader(String name, ClassLoader parent) {
this(checkCreateClassLoader(name), name, parent);
}
-
/**
* Creates a new class loader using the specified parent class loader for
* delegation.
@@ -440,6 +442,7 @@ public abstract class ClassLoader {
* this class loader is not named.
*
* @since 9
+ * @spec JPMS
*/
public String getName() {
return name;
@@ -710,6 +713,7 @@ public abstract class ClassLoader {
* if the class could not be found.
*
* @since 9
+ * @spec JPMS
*/
protected Class> findClass(String moduleName, String name) {
if (moduleName == null) {
@@ -834,6 +838,8 @@ public abstract class ClassLoader {
* @see java.security.SecureClassLoader
*
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
protected final Class> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError
@@ -967,6 +973,9 @@ public abstract class ClassLoader {
* certificates than this class, or if {@code name} begins with
* "{@code java.}" and this class loader is not the platform
* class loader or its ancestor.
+ *
+ * @revised 9
+ * @spec JPMS
*/
protected final Class> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain)
@@ -1041,6 +1050,8 @@ public abstract class ClassLoader {
* @see #defineClass(String, byte[], int, int, ProtectionDomain)
*
* @since 1.5
+ * @revised 9
+ * @spec JPMS
*/
protected final Class> defineClass(String name, java.nio.ByteBuffer b,
ProtectionDomain protectionDomain)
@@ -1264,11 +1275,11 @@ public abstract class ClassLoader {
* Class loader implementations that support the loading from modules
* should override this method.
*
- * @apiNote This method is the basis for the {@code Class} {@link
- * Class#getResource getResource} and {@link Class#getResourceAsStream
- * getResourceAsStream} methods. It is not subject to the rules for
- * encapsulation specified by {@code Module} {@link
- * Module#getResourceAsStream getResourceAsStream}.
+ * @apiNote This method is the basis for the {@link
+ * Class#getResource Class.getResource}, {@link Class#getResourceAsStream
+ * Class.getResourceAsStream}, and {@link Module#getResourceAsStream
+ * Module.getResourceAsStream} methods. It is not subject to the rules for
+ * encapsulation specified by {@code Module.getResourceAsStream}.
*
* @implSpec The default implementation attempts to find the resource by
* invoking {@link #findResource(String)} when the {@code moduleName} is
@@ -1292,6 +1303,7 @@ public abstract class ClassLoader {
*
* @see java.lang.module.ModuleReader#find(String)
* @since 9
+ * @spec JPMS
*/
protected URL findResource(String moduleName, String name) throws IOException {
if (moduleName == null) {
@@ -1342,6 +1354,8 @@ public abstract class ClassLoader {
* @throws NullPointerException If {@code name} is {@code null}
*
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
public URL getResource(String name) {
Objects.requireNonNull(name);
@@ -1403,6 +1417,8 @@ public abstract class ClassLoader {
* @see #findResources(String)
*
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
public Enumeration getResources(String name) throws IOException {
Objects.requireNonNull(name);
@@ -1499,6 +1515,8 @@ public abstract class ClassLoader {
* denied by the security manager.
*
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
protected URL findResource(String name) {
return null;
@@ -1531,6 +1549,8 @@ public abstract class ClassLoader {
* If I/O errors occur
*
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
protected Enumeration findResources(String name) throws IOException {
return Collections.emptyEnumeration();
@@ -1601,6 +1621,8 @@ public abstract class ClassLoader {
* denied by the security manager.
*
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
public static URL getSystemResource(String name) {
return getSystemClassLoader().getResource(name);
@@ -1636,6 +1658,8 @@ public abstract class ClassLoader {
* If I/O errors occur
*
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
public static Enumeration getSystemResources(String name)
throws IOException
@@ -1667,6 +1691,8 @@ public abstract class ClassLoader {
* @throws NullPointerException If {@code name} is {@code null}
*
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
public InputStream getResourceAsStream(String name) {
Objects.requireNonNull(name);
@@ -1699,6 +1725,8 @@ public abstract class ClassLoader {
* denied by the security manager.
*
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
public static InputStream getSystemResourceAsStream(String name) {
URL url = getSystemResource(name);
@@ -1749,6 +1777,7 @@ public abstract class ClassLoader {
*
* @see Module#isNamed()
* @since 9
+ * @spec JPMS
*/
public final Module getUnnamedModule() {
return unnamedModule;
@@ -1772,6 +1801,7 @@ public abstract class ClassLoader {
* {@link RuntimePermission}{@code ("getClassLoader")}
*
* @since 9
+ * @spec JPMS
*/
@CallerSensitive
public static ClassLoader getPlatformClassLoader() {
@@ -1847,6 +1877,8 @@ public abstract class ClassLoader {
* {@link Throwable#getCause()} method.
*
* @revised 1.4
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static ClassLoader getSystemClassLoader() {
@@ -2101,6 +2133,8 @@ public abstract class ClassLoader {
* defined by this class loader
*
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*
* @see
* The JAR File Specification: Package Versioning
@@ -2138,6 +2172,7 @@ public abstract class ClassLoader {
* if {@code name} is {@code null}.
*
* @since 9
+ * @spec JPMS
*/
public final Package getDefinedPackage(String name) {
Objects.requireNonNull(name, "name cannot be null");
@@ -2160,6 +2195,7 @@ public abstract class ClassLoader {
* or an zero length array if no package has been defined by this class loader.
*
* @since 9
+ * @spec JPMS
*/
public final Package[] getDefinedPackages() {
return packages().toArray(Package[]::new);
@@ -2196,6 +2232,8 @@ public abstract class ClassLoader {
* a {@code Package} for the specified class loader.
*
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
@Deprecated(since="9")
protected Package getPackage(String name) {
@@ -2220,6 +2258,8 @@ public abstract class ClassLoader {
* class loader and its ancestors
*
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
protected Package[] getPackages() {
Stream pkgs = packages();
diff --git a/jdk/src/java.base/share/classes/java/lang/IllegalCallerException.java b/jdk/src/java.base/share/classes/java/lang/IllegalCallerException.java
new file mode 100644
index 00000000000..f882fb21591
--- /dev/null
+++ b/jdk/src/java.base/share/classes/java/lang/IllegalCallerException.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that a method has been called by an inappropriate caller.
+ *
+ * @since 9
+ * @spec JPMS
+ * @see StackWalker#getCallerClass
+ */
+public class IllegalCallerException extends RuntimeException {
+ /**
+ * Constructs an IllegalCallerException with no detail message.
+ */
+ public IllegalCallerException() {
+ super();
+ }
+
+ /**
+ * Constructs an IllegalCallerException with the specified detail
+ * message.
+ *
+ * @param s the String that contains a detailed message (can be null)
+ */
+ public IllegalCallerException(String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and
+ * cause.
+ *
+ * @param message the detail message (can be null)
+ * @param cause the cause (can be null)
+ */
+ public IllegalCallerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new exception with the specified cause and a detail
+ * message of {@code (cause==null ? null : cause.toString())} (which
+ * typically contains the class and detail message of {@code cause}).
+ *
+ * @param cause the cause (can be null)
+ */
+ public IllegalCallerException(Throwable cause) {
+ super(cause);
+ }
+
+ static final long serialVersionUID = -2349421918363102232L;
+}
diff --git a/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java b/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java
index 5be48729d5a..612ff09f138 100644
--- a/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java
+++ b/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -55,14 +55,36 @@ interface LiveStackFrame extends StackFrame {
*
*
A single local variable can hold a value of type boolean, byte, char,
* short, int, float, reference or returnAddress. A pair of local variables
- * can hold a value of type long or double. In other words,
- * a value of type long or type double occupies two consecutive local
- * variables. For a value of primitive type, the element in the
- * local variable array is an {@link PrimitiveValue} object;
- * otherwise, the element is an {@code Object}.
+ * can hold a value of type long or double (JVMS section 2.6.1). Primitive
+ * locals are represented in the returned array as {@code PrimitiveSlot}s,
+ * with longs and doubles occupying a pair of consecutive
+ * {@code PrimitiveSlot}s.
*
- *
The returned array may contain null entries if a local variable is not
- * live.
+ *
The current VM implementation does not provide specific type
+ * information for primitive locals. This method simply returns the raw
+ * contents of the VM's primitive locals on a best-effort basis, without
+ * indicating a specific type.
+ *
+ *
The returned array may contain null entries for local variables that
+ * are not live.
+ *
+ * @implNote
+ *
The specific subclass of {@code PrimitiveSlot} will reflect the
+ * underlying architecture, and will be either {@code PrimitiveSlot32} or
+ * {@code PrimitiveSlot64}.
+ *
+ *
How a long or double value is stored in the pair of
+ * {@code PrimitiveSlot}s can vary based on the underlying architecture and
+ * VM implementation. On 32-bit architectures, long/double values are split
+ * between the two {@code PrimitiveSlot32}s.
+ * On 64-bit architectures, the entire value may be stored in one of the
+ * {@code PrimitiveSlot64}s, with the other {@code PrimitiveSlot64} being
+ * unused.
+ *
+ *
The contents of the unused, high-order portion of a
+ * {@code PrimitiveSlot64} (when storing a primitive other than a long or
+ * double) is unspecified. In particular, the unused bits are not
+ * necessarily zeroed out.
*
* @return the local variable array of this stack frame.
*/
@@ -78,7 +100,7 @@ interface LiveStackFrame extends StackFrame {
*
Each entry on the operand stack can hold a value of any Java Virtual
* Machine Type.
* For a value of primitive type, the element in the returned array is
- * an {@link PrimitiveValue} object; otherwise, the element is the {@code Object}
+ * a {@link PrimitiveSlot} object; otherwise, the element is the {@code Object}
* on the operand stack.
*
* @return the operand stack of this stack frame.
@@ -87,107 +109,37 @@ interface LiveStackFrame extends StackFrame {
/**
* UNSUPPORTED This interface is intended to be package-private
- * or move to an internal package.
+ * or moved to an internal package.
*
- * Represents a local variable or an entry on the operand whose value is
+ * Represents a local variable or an entry on the operand stack whose value is
* of primitive type.
*/
- public abstract class PrimitiveValue {
+ public abstract class PrimitiveSlot {
/**
- * Returns the base type of this primitive value, one of
- * {@code B, D, C, F, I, J, S, Z}.
- *
- * @return Name of a base type
- * @jvms table 4.3-A
+ * Returns the size, in bytes, of the slot.
*/
- abstract char type();
+ public abstract int size();
/**
- * Returns the boolean value if this primitive value is of type boolean.
- * @return the boolean value if this primitive value is of type boolean.
+ * Returns the int value if this primitive value is of size 4
+ * @return the int value if this primitive value is of size 4
*
* @throws UnsupportedOperationException if this primitive value is not
- * of type boolean.
- */
- public boolean booleanValue() {
- throw new UnsupportedOperationException("this primitive of type " + type());
- }
-
- /**
- * Returns the int value if this primitive value is of type int.
- * @return the int value if this primitive value is of type int.
- *
- * @throws UnsupportedOperationException if this primitive value is not
- * of type int.
+ * of size 4.
*/
public int intValue() {
- throw new UnsupportedOperationException("this primitive of type " + type());
+ throw new UnsupportedOperationException("this " + size() + "-byte primitive");
}
/**
- * Returns the long value if this primitive value is of type long.
- * @return the long value if this primitive value is of type long.
+ * Returns the long value if this primitive value is of size 8
+ * @return the long value if this primitive value is of size 8
*
* @throws UnsupportedOperationException if this primitive value is not
- * of type long.
+ * of size 8.
*/
public long longValue() {
- throw new UnsupportedOperationException("this primitive of type " + type());
- }
-
- /**
- * Returns the char value if this primitive value is of type char.
- * @return the char value if this primitive value is of type char.
- *
- * @throws UnsupportedOperationException if this primitive value is not
- * of type char.
- */
- public char charValue() {
- throw new UnsupportedOperationException("this primitive of type " + type());
- }
-
- /**
- * Returns the byte value if this primitive value is of type byte.
- * @return the byte value if this primitive value is of type byte.
- *
- * @throws UnsupportedOperationException if this primitive value is not
- * of type byte.
- */
- public byte byteValue() {
- throw new UnsupportedOperationException("this primitive of type " + type());
- }
-
- /**
- * Returns the short value if this primitive value is of type short.
- * @return the short value if this primitive value is of type short.
- *
- * @throws UnsupportedOperationException if this primitive value is not
- * of type short.
- */
- public short shortValue() {
- throw new UnsupportedOperationException("this primitive of type " + type());
- }
-
- /**
- * Returns the float value if this primitive value is of type float.
- * @return the float value if this primitive value is of type float.
- *
- * @throws UnsupportedOperationException if this primitive value is not
- * of type float.
- */
- public float floatValue() {
- throw new UnsupportedOperationException("this primitive of type " + type());
- }
-
- /**
- * Returns the double value if this primitive value is of type double.
- * @return the double value if this primitive value is of type double.
- *
- * @throws UnsupportedOperationException if this primitive value is not
- * of type double.
- */
- public double doubleValue() {
- throw new UnsupportedOperationException("this primitive of type " + type());
+ throw new UnsupportedOperationException("this " + size() + "-byte primitive");
}
}
diff --git a/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java b/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java
index db8901ea731..b6583adf559 100644
--- a/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java
+++ b/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,15 +24,13 @@
*/
package java.lang;
-import java.lang.StackWalker.Option;
-import java.util.EnumSet;
-import java.util.Set;
-
-import static java.lang.StackWalker.ExtendedOption.*;
-
final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame {
private static Object[] EMPTY_ARRAY = new Object[0];
+ // These flags must match the values maintained in the VM
+ private static final int MODE_INTERPRETED = 0x01;
+ private static final int MODE_COMPILED = 0x02;
+
LiveStackFrameInfo(StackWalker walker) {
super(walker);
}
@@ -41,6 +39,7 @@ final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame
private Object[] monitors = EMPTY_ARRAY;
private Object[] locals = EMPTY_ARRAY;
private Object[] operands = EMPTY_ARRAY;
+ private int mode = 0;
@Override
public Object[] getMonitors() {
@@ -57,51 +56,44 @@ final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame
return operands;
}
+ @Override
+ public String toString() {
+ StringBuilder retVal = new StringBuilder(super.toString());
+ if (mode != 0) {
+ retVal.append("(");
+ if ((mode & MODE_INTERPRETED) == MODE_INTERPRETED) {
+ retVal.append(" interpreted ");
+ }
+ if ((mode & MODE_COMPILED) == MODE_COMPILED) {
+ retVal.append(" compiled ");
+ }
+ retVal.append(")");
+ }
+ return retVal.toString();
+ }
+
/*
- * Convert primitive value to {@code Primitive} object to represent
+ * Convert primitive value to {@code PrimitiveSlot} object to represent
* a local variable or an element on the operand stack of primitive type.
*/
- static PrimitiveValue asPrimitive(boolean value) {
- return new BooleanPrimitive(value);
+
+ static PrimitiveSlot asPrimitive(int value) {
+ return new PrimitiveSlot32(value);
}
- static PrimitiveValue asPrimitive(int value) {
- return new IntPrimitive(value);
+ static PrimitiveSlot asPrimitive(long value) {
+ return new PrimitiveSlot64(value);
}
- static PrimitiveValue asPrimitive(short value) {
- return new ShortPrimitive(value);
- }
-
- static PrimitiveValue asPrimitive(char value) {
- return new CharPrimitive(value);
- }
-
- static PrimitiveValue asPrimitive(byte value) {
- return new BytePrimitive(value);
- }
-
- static PrimitiveValue asPrimitive(long value) {
- return new LongPrimitive(value);
- }
-
- static PrimitiveValue asPrimitive(float value) {
- return new FloatPrimitive(value);
- }
-
- static PrimitiveValue asPrimitive(double value) {
- return new DoublePrimitive(value);
- }
-
- private static class IntPrimitive extends PrimitiveValue {
+ private static class PrimitiveSlot32 extends PrimitiveSlot {
final int value;
- IntPrimitive(int value) {
+ PrimitiveSlot32(int value) {
this.value = value;
}
@Override
- public char type() {
- return 'I';
+ public int size() {
+ return 4;
}
@Override
@@ -115,103 +107,15 @@ final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame
}
}
- private static class ShortPrimitive extends PrimitiveValue {
- final short value;
- ShortPrimitive(short value) {
- this.value = value;
- }
-
- @Override
- public char type() {
- return 'S';
- }
-
- @Override
- public short shortValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
-
- private static class BooleanPrimitive extends PrimitiveValue {
- final boolean value;
- BooleanPrimitive(boolean value) {
- this.value = value;
- }
-
- @Override
- public char type() {
- return 'Z';
- }
-
- @Override
- public boolean booleanValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
-
- private static class CharPrimitive extends PrimitiveValue {
- final char value;
- CharPrimitive(char value) {
- this.value = value;
- }
-
- @Override
- public char type() {
- return 'C';
- }
-
- @Override
- public char charValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
-
- private static class BytePrimitive extends PrimitiveValue {
- final byte value;
- BytePrimitive(byte value) {
- this.value = value;
- }
-
- @Override
- public char type() {
- return 'B';
- }
-
- @Override
- public byte byteValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
-
- private static class LongPrimitive extends PrimitiveValue {
+ private static class PrimitiveSlot64 extends PrimitiveSlot {
final long value;
- LongPrimitive(long value) {
+ PrimitiveSlot64(long value) {
this.value = value;
}
@Override
- public char type() {
- return 'J';
+ public int size() {
+ return 8;
}
@Override
@@ -224,48 +128,4 @@ final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame
return String.valueOf(value);
}
}
-
- private static class FloatPrimitive extends PrimitiveValue {
- final float value;
- FloatPrimitive(float value) {
- this.value = value;
- }
-
- @Override
- public char type() {
- return 'F';
- }
-
- @Override
- public float floatValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
-
- private static class DoublePrimitive extends PrimitiveValue {
- final double value;
- DoublePrimitive(double value) {
- this.value = value;
- }
-
- @Override
- public char type() {
- return 'D';
- }
-
- @Override
- public double doubleValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
}
diff --git a/jdk/src/java.base/share/classes/java/lang/Package.java b/jdk/src/java.base/share/classes/java/lang/Package.java
index 5a19f9771f1..0dcc5e1c12c 100644
--- a/jdk/src/java.base/share/classes/java/lang/Package.java
+++ b/jdk/src/java.base/share/classes/java/lang/Package.java
@@ -111,6 +111,8 @@ import jdk.internal.reflect.Reflection;
* @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL)
*
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
public class Package extends NamedPackage implements java.lang.reflect.AnnotatedElement {
/**
@@ -207,6 +209,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated
* is returned if it is not known.
* @return the vendor that implemented this package, {@code null}
* is returned if it is not known.
+ *
+ * @revised 9
+ * @spec JPMS
*/
public String getImplementationVendor() {
return versionInfo.implVendor;
@@ -334,6 +339,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated
* a {@code Package} for the specified class loader.
*
* @see ClassLoader#getDefinedPackage
+ *
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
@Deprecated(since="9")
@@ -356,6 +364,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated
* class loader and its ancestors
*
* @see ClassLoader#getDefinedPackages
+ *
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static Package[] getPackages() {
diff --git a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java
index 8a819ee6db7..084d4661700 100644
--- a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java
+++ b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java
@@ -1457,6 +1457,18 @@ class SecurityManager {
.collect(Collectors.toSet());
}
+ /**
+ * Called by java.security.Security
+ */
+ static void invalidatePackageAccessCache() {
+ synchronized (packageAccessLock) {
+ packageAccessValid = false;
+ }
+ synchronized (packageDefinitionLock) {
+ packageDefinitionValid = false;
+ }
+ }
+
/**
* Returns true if the module's loader is the boot or platform loader.
*/
diff --git a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java
index 55976485d4f..4fd03331229 100644
--- a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java
+++ b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java
@@ -25,11 +25,13 @@
package java.lang;
import jdk.internal.reflect.MethodAccessor;
+import jdk.internal.reflect.ConstructorAccessor;
import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.annotation.Native;
import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -684,7 +686,7 @@ final class StackStreamFactory {
frames[n++] = caller;
}
if (frames[1] == null) {
- throw new IllegalStateException("no caller frame");
+ throw new IllegalCallerException("no caller frame");
}
return n;
}
@@ -922,7 +924,8 @@ final class StackStreamFactory {
*/
final void setBatch(int depth, int startIndex, int endIndex) {
if (startIndex <= 0 || endIndex <= 0)
- throw new IllegalArgumentException("startIndex=" + startIndex + " endIndex=" + endIndex);
+ throw new IllegalArgumentException("startIndex=" + startIndex
+ + " endIndex=" + endIndex);
this.origin = startIndex;
this.fence = endIndex;
@@ -980,13 +983,18 @@ final class StackStreamFactory {
private static boolean isReflectionFrame(Class> c) {
if (c.getName().startsWith("jdk.internal.reflect") &&
- !MethodAccessor.class.isAssignableFrom(c)) {
- throw new InternalError("Not jdk.internal.reflect.MethodAccessor: " + c.toString());
+ !MethodAccessor.class.isAssignableFrom(c) &&
+ !ConstructorAccessor.class.isAssignableFrom(c)) {
+ throw new InternalError("Not jdk.internal.reflect.MethodAccessor"
+ + " or jdk.internal.reflect.ConstructorAccessor: "
+ + c.toString());
}
// ## should filter all @Hidden frames?
return c == Method.class ||
- MethodAccessor.class.isAssignableFrom(c) ||
- c.getName().startsWith("java.lang.invoke.LambdaForm");
+ c == Constructor.class ||
+ MethodAccessor.class.isAssignableFrom(c) ||
+ ConstructorAccessor.class.isAssignableFrom(c) ||
+ c.getName().startsWith("java.lang.invoke.LambdaForm");
}
}
diff --git a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java
index d95ea5ef826..79b4c7299f6 100644
--- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java
+++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java
@@ -92,6 +92,8 @@ public final class StackTraceElement implements java.io.Serializable {
* @throws NullPointerException if {@code declaringClass} or
* {@code methodName} is null
* @since 1.5
+ * @revised 9
+ * @spec JPMS
*/
public StackTraceElement(String declaringClass, String methodName,
String fileName, int lineNumber) {
@@ -128,6 +130,7 @@ public final class StackTraceElement implements java.io.Serializable {
* or {@code methodName} is {@code null}
*
* @since 9
+ * @spec JPMS
*/
public StackTraceElement(String classLoaderName,
String moduleName, String moduleVersion,
@@ -187,6 +190,7 @@ public final class StackTraceElement implements java.io.Serializable {
* point represented by this stack trace element; {@code null}
* if the module name is not available.
* @since 9
+ * @spec JPMS
* @see java.lang.reflect.Module#getName()
*/
public String getModuleName() {
@@ -201,6 +205,7 @@ public final class StackTraceElement implements java.io.Serializable {
* point represented by this stack trace element; {@code null}
* if the module version is not available.
* @since 9
+ * @spec JPMS
* @see java.lang.module.ModuleDescriptor.Version
*/
public String getModuleVersion() {
@@ -216,6 +221,7 @@ public final class StackTraceElement implements java.io.Serializable {
* if the class loader is not named.
*
* @since 9
+ * @spec JPMS
* @see java.lang.ClassLoader#getName()
*/
public String getClassLoaderName() {
@@ -329,6 +335,8 @@ public final class StackTraceElement implements java.io.Serializable {
* {@link java.lang.StackWalker.StackFrame}, where an implementation may
* choose to omit some element in the returned string.
*
+ * @revised 9
+ * @spec JPMS
* @see Throwable#printStackTrace()
*/
public String toString() {
@@ -376,6 +384,9 @@ public final class StackTraceElement implements java.io.Serializable {
* @return true if the specified object is another
* {@code StackTraceElement} instance representing the same
* execution point as this instance.
+ *
+ * @revised 9
+ * @spec JPMS
*/
public boolean equals(Object obj) {
if (obj==this)
diff --git a/jdk/src/java.base/share/classes/java/lang/StackWalker.java b/jdk/src/java.base/share/classes/java/lang/StackWalker.java
index b5c43fd2d67..52d9637c138 100644
--- a/jdk/src/java.base/share/classes/java/lang/StackWalker.java
+++ b/jdk/src/java.base/share/classes/java/lang/StackWalker.java
@@ -29,6 +29,7 @@ import jdk.internal.reflect.CallerSensitive;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.stream.Stream;
/**
@@ -207,13 +208,23 @@ public final class StackWalker {
/**
* Shows all reflection frames.
*
- *
By default, reflection frames are hidden. This includes the
- * {@link java.lang.reflect.Method#invoke} method
- * and the reflection implementation classes. A {@code StackWalker} with
- * this {@code SHOW_REFLECT_FRAMES} option will show all reflection frames.
- * The {@link #SHOW_HIDDEN_FRAMES} option can also be used to show all
+ *
By default, reflection frames are hidden. A {@code StackWalker}
+ * configured with this {@code SHOW_REFLECT_FRAMES} option
+ * will show all reflection frames that
+ * include {@link java.lang.reflect.Method#invoke} and
+ * {@link java.lang.reflect.Constructor#newInstance(Object...)}
+ * and their reflection implementation classes.
+ *
+ *
The {@link #SHOW_HIDDEN_FRAMES} option can also be used to show all
* reflection frames and it will also show other hidden frames that
* are implementation-specific.
+ *
+ * @apiNote
+ * This option includes the stack frames representing the invocation of
+ * {@code Method} and {@code Constructor}. Any utility methods that
+ * are equivalent to calling {@code Method.invoke} or
+ * {@code Constructor.newInstance} such as {@code Class.newInstance}
+ * are not filtered or controlled by any stack walking option.
*/
SHOW_REFLECT_FRAMES,
/**
@@ -465,28 +476,31 @@ public final class StackWalker {
}
/**
- * Gets the {@code Class} object of the caller invoking the method
- * that calls this {@code getCallerClass} method.
+ * Gets the {@code Class} object of the caller who invoked the method
+ * that invoked {@code getCallerClass}.
*
- *
Reflection frames, {@link java.lang.invoke.MethodHandle}, and
- * hidden frames are filtered regardless of the
+ *
This method filters {@linkplain Option#SHOW_REFLECT_FRAMES reflection
+ * frames}, {@link java.lang.invoke.MethodHandle}, and
+ * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} regardless of the
* {@link Option#SHOW_REFLECT_FRAMES SHOW_REFLECT_FRAMES}
* and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options
* this {@code StackWalker} has been configured with.
*
+ *
This method should be called when a caller frame is present. If
+ * it is called from the bottom most frame on the stack,
+ * {@code IllegalCallerException} will be thrown.
+ *
*
This method throws {@code UnsupportedOperationException}
* if this {@code StackWalker} is not configured with the
* {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option.
- * This method should be called when a caller frame is present. If
- * it is called from the last frame on the stack,
- * {@code IllegalStateException} will be thrown.
*
* @apiNote
* For example, {@code Util::getResourceBundle} loads a resource bundle
- * on behalf of the caller. It calls this {@code getCallerClass} method
- * to find the method calling {@code Util::getResourceBundle} and uses the caller's
- * class loader to load the resource bundle. The caller class in this example
- * is the {@code MyTool} class.
+ * on behalf of the caller. It invokes {@code getCallerClass} to identify
+ * the class whose method called {@code Util::getResourceBundle}.
+ * Then, it obtains the class loader of that class, and uses
+ * the class loader to load the resource bundle. The caller class
+ * in this example is {@code MyTool}.
*
*
{@code
* class Util {
@@ -517,17 +531,17 @@ public final class StackWalker {
* }
*
* When the {@code getCallerClass} method is called from a method that
- * is the last frame on the stack,
+ * is the bottom most frame on the stack,
* for example, {@code static public void main} method launched by the
* {@code java} launcher, or a method invoked from a JNI attached thread,
- * {@code IllegalStateException} is thrown.
+ * {@code IllegalCallerException} is thrown.
*
* @return {@code Class} object of the caller's caller invoking this method.
*
* @throws UnsupportedOperationException if this {@code StackWalker}
* is not configured with {@link Option#RETAIN_CLASS_REFERENCE
* Option.RETAIN_CLASS_REFERENCE}.
- * @throws IllegalStateException if there is no caller frame, i.e.
+ * @throws IllegalCallerException if there is no caller frame, i.e.
* when this {@code getCallerClass} method is called from a method
* which is the last frame on the stack.
*/
diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java
index 1577e215e35..106ad0fb291 100644
--- a/jdk/src/java.base/share/classes/java/lang/System.java
+++ b/jdk/src/java.base/share/classes/java/lang/System.java
@@ -1942,13 +1942,12 @@ public final class System {
* the application classpath or modulepath.
*/
private static void initPhase3() {
- // Initialize publicLookup early, to avoid bootstrapping circularities
- // with security manager using java.lang.invoke infrastructure.
- java.lang.invoke.MethodHandles.publicLookup();
-
// set security manager
String cn = System.getProperty("java.security.manager");
if (cn != null) {
+ // ensure image reader for java.base is initialized before security manager
+ Object.class.getResource("module-info.class");
+
if (cn.isEmpty() || "default".equals(cn)) {
System.setSecurityManager(new SecurityManager());
} else {
@@ -2053,6 +2052,9 @@ public final class System {
public String fastUUID(long lsb, long msb) {
return Long.fastUUID(lsb, msb);
}
+ public void invalidatePackageAccessCache() {
+ SecurityManager.invalidatePackageAccessCache();
+ }
});
}
}
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java
index 3f91060ccc8..0675c043185 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java
@@ -141,6 +141,18 @@ import static sun.invoke.util.Wrapper.isWrapperType;
this.markerInterfaces = markerInterfaces;
this.additionalBridges = additionalBridges;
+ if (samMethodName.isEmpty() ||
+ samMethodName.indexOf('.') >= 0 ||
+ samMethodName.indexOf(';') >= 0 ||
+ samMethodName.indexOf('[') >= 0 ||
+ samMethodName.indexOf('/') >= 0 ||
+ samMethodName.indexOf('<') >= 0 ||
+ samMethodName.indexOf('>') >= 0) {
+ throw new LambdaConversionException(String.format(
+ "Method name '%s' is not legal",
+ samMethodName));
+ }
+
if (!samBase.isInterface()) {
throw new LambdaConversionException(String.format(
"Functional interface %s is not an interface",
@@ -275,25 +287,39 @@ import static sun.invoke.util.Wrapper.isWrapperType;
(implKind == MethodHandleInfo.REF_newInvokeSpecial)
? implDefiningClass
: implMethodType.returnType();
- Class> samReturnType = samMethodType.returnType();
if (!isAdaptableToAsReturn(actualReturnType, expectedType)) {
throw new LambdaConversionException(
String.format("Type mismatch for lambda return: %s is not convertible to %s",
actualReturnType, expectedType));
}
- if (!isAdaptableToAsReturnStrict(expectedType, samReturnType)) {
- throw new LambdaConversionException(
- String.format("Type mismatch for lambda expected return: %s is not convertible to %s",
- expectedType, samReturnType));
- }
+
+ // Check descriptors of generated methods
+ checkDescriptor(samMethodType);
for (MethodType bridgeMT : additionalBridges) {
- if (!isAdaptableToAsReturnStrict(expectedType, bridgeMT.returnType())) {
- throw new LambdaConversionException(
- String.format("Type mismatch for lambda expected return: %s is not convertible to %s",
- expectedType, bridgeMT.returnType()));
+ checkDescriptor(bridgeMT);
+ }
+ }
+
+ /** Validate that the given descriptor's types are compatible with {@code instantiatedMethodType} **/
+ private void checkDescriptor(MethodType descriptor) throws LambdaConversionException {
+ for (int i = 0; i < instantiatedMethodType.parameterCount(); i++) {
+ Class> instantiatedParamType = instantiatedMethodType.parameterType(i);
+ Class> descriptorParamType = descriptor.parameterType(i);
+ if (!descriptorParamType.isAssignableFrom(instantiatedParamType)) {
+ String msg = String.format("Type mismatch for instantiated parameter %d: %s is not a subtype of %s",
+ i, instantiatedParamType, descriptorParamType);
+ throw new LambdaConversionException(msg);
}
}
- }
+
+ Class> instantiatedReturnType = instantiatedMethodType.returnType();
+ Class> descriptorReturnType = descriptor.returnType();
+ if (!isAdaptableToAsReturnStrict(instantiatedReturnType, descriptorReturnType)) {
+ String msg = String.format("Type mismatch for lambda expected return: %s is not convertible to %s",
+ instantiatedReturnType, descriptorReturnType);
+ throw new LambdaConversionException(msg);
+ }
+ }
/**
* Check type adaptability for parameter types.
@@ -345,8 +371,8 @@ import static sun.invoke.util.Wrapper.isWrapperType;
|| !fromType.equals(void.class) && isAdaptableTo(fromType, toType, false);
}
private boolean isAdaptableToAsReturnStrict(Class> fromType, Class> toType) {
- if (fromType.equals(void.class)) return toType.equals(void.class);
- return isAdaptableTo(fromType, toType, true);
+ if (fromType.equals(void.class) || toType.equals(void.class)) return fromType.equals(toType);
+ else return isAdaptableTo(fromType, toType, true);
}
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index 16a9e8a941d..98f02d0f19f 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -25,8 +25,6 @@
package java.lang.invoke;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.ForceInline;
@@ -111,13 +109,17 @@ public class MethodHandles {
/**
* Returns a {@link Lookup lookup object} which is trusted minimally.
- * It can only be used to create method handles to public members in
+ * The lookup has the {@code PUBLIC} and {@code UNCONDITIONAL} modes.
+ * It can only be used to create method handles to public members of
* public classes in packages that are exported unconditionally.
*
- * For now, the {@linkplain Lookup#lookupClass lookup class} of this lookup
- * object is in an unnamed module.
- * Consequently, the lookup context of this lookup object will be the bootstrap
- * class loader, which means it cannot find user classes.
+ * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
+ * of this lookup object will be {@link java.lang.Object}.
+ *
+ * @apiNote The use of Object is conventional, and because the lookup modes are
+ * limited, there is no special access provided to the internals of Object, its package
+ * or its module. Consequently, the lookup context of this lookup object will be the
+ * bootstrap class loader, which means it cannot find user classes.
*
*
* Discussion:
@@ -129,17 +131,12 @@ public class MethodHandles {
* Also, it cannot access
* caller sensitive methods.
* @return a lookup object which is trusted minimally
+ *
+ * @revised 9
+ * @spec JPMS
*/
public static Lookup publicLookup() {
- // During VM startup then only classes in the java.base module can be
- // loaded and linked. This is because java.base exports aren't setup until
- // the module system is initialized, hence types in the unnamed module
- // (or any named module) can't link to java/lang/Object.
- if (!jdk.internal.misc.VM.isModuleSystemInited()) {
- return new Lookup(Object.class, Lookup.PUBLIC);
- } else {
- return LookupHelper.PUBLIC_LOOKUP;
- }
+ return Lookup.PUBLIC_LOOKUP;
}
/**
@@ -172,6 +169,7 @@ public class MethodHandles {
* @throws IllegalAccessException if the access check specified above fails
* @throws SecurityException if denied by the security manager
* @since 9
+ * @spec JPMS
* @see Lookup#dropLookupMode
*/
public static Lookup privateLookupIn(Class> targetClass, Lookup lookup) throws IllegalAccessException {
@@ -183,11 +181,11 @@ public class MethodHandles {
throw new IllegalArgumentException(targetClass + " is an array class");
Module targetModule = targetClass.getModule();
Module callerModule = lookup.lookupClass().getModule();
- if (callerModule != targetModule && targetModule.isNamed()) {
- if (!callerModule.canRead(targetModule))
- throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+ if (!callerModule.canRead(targetModule))
+ throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+ if (targetModule.isNamed()) {
String pn = targetClass.getPackageName();
- assert pn != null && pn.length() > 0 : "unnamed package cannot be in named module";
+ assert pn.length() > 0 : "unnamed package cannot be in named module";
if (!targetModule.isOpen(pn, callerModule))
throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
}
@@ -601,6 +599,8 @@ public class MethodHandles {
* so that there can be a secure foundation for lookups.
* Nearly all other methods in the JSR 292 API rely on lookup
* objects to check access requests.
+ *
+ * @revised 9
*/
public static final
class Lookup {
@@ -647,15 +647,33 @@ public class MethodHandles {
* lookup class and public types in packages exported by other modules
* to the module of the lookup class.
* @since 9
+ * @spec JPMS
*/
public static final int MODULE = PACKAGE << 1;
- private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE);
+ /** A single-bit mask representing {@code unconditional} access
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value is {@code 0x20}, which does not correspond meaningfully to
+ * any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+ * A {@code Lookup} with this lookup mode assumes {@linkplain
+ * java.lang.reflect.Module#canRead(java.lang.reflect.Module) readability}.
+ * In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup}
+ * with this lookup mode can access all public members of public types
+ * of all modules where the type is in a package that is {@link
+ * java.lang.reflect.Module#isExported(String) exported unconditionally}.
+ * @since 9
+ * @spec JPMS
+ * @see #publicLookup()
+ */
+ public static final int UNCONDITIONAL = PACKAGE << 2;
+
+ private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE | UNCONDITIONAL);
+ private static final int FULL_POWER_MODES = (ALL_MODES & ~UNCONDITIONAL);
private static final int TRUSTED = -1;
private static int fixmods(int mods) {
- mods &= (ALL_MODES - PACKAGE - MODULE);
- return (mods != 0) ? mods : (PACKAGE | MODULE);
+ mods &= (ALL_MODES - PACKAGE - MODULE - UNCONDITIONAL);
+ return (mods != 0) ? mods : (PACKAGE | MODULE | UNCONDITIONAL);
}
/** Tells which class is performing the lookup. It is this class against
@@ -682,13 +700,14 @@ public class MethodHandles {
* {@linkplain #PRIVATE PRIVATE (0x02)},
* {@linkplain #PROTECTED PROTECTED (0x04)},
* {@linkplain #PACKAGE PACKAGE (0x08)},
- * and {@linkplain #MODULE MODULE (0x10)}.
+ * {@linkplain #MODULE MODULE (0x10)},
+ * and {@linkplain #UNCONDITIONAL UNCONDITIONAL (0x20)}.
*
* A freshly-created lookup object
- * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
- * has all possible bits set, since the caller class can access all its own members,
- * all public types in the caller's module, and all public types in packages exported
- * by other modules to the caller's module.
+ * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class} has
+ * all possible bits set, except {@code UNCONDITIONAL}. The lookup can be used to
+ * access all members of the caller's class, all public types in the caller's module,
+ * and all public types in packages exported by other modules to the caller's module.
* A lookup object on a new lookup class
* {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
* may have some mode bits set to zero.
@@ -701,6 +720,9 @@ public class MethodHandles {
* @return the lookup modes, which limit the kinds of access performed by this lookup object
* @see #in
* @see #dropLookupMode
+ *
+ * @revised 9
+ * @spec JPMS
*/
public int lookupModes() {
return allowedModes & ALL_MODES;
@@ -712,9 +734,9 @@ public class MethodHandles {
* which in turn is called by a method not in this package.
*/
Lookup(Class> lookupClass) {
- this(lookupClass, ALL_MODES);
+ this(lookupClass, FULL_POWER_MODES);
// make sure we haven't accidentally picked up a privileged class:
- checkUnprivilegedlookupClass(lookupClass, ALL_MODES);
+ checkUnprivilegedlookupClass(lookupClass, FULL_POWER_MODES);
}
private Lookup(Class> lookupClass, int allowedModes) {
@@ -730,19 +752,20 @@ public class MethodHandles {
* However, the resulting {@code Lookup} object is guaranteed
* to have no more access capabilities than the original.
* In particular, access capabilities can be lost as follows:
- *
If the lookup class for this {@code Lookup} is not in a named module,
- * and the new lookup class is in a named module {@code M}, then no members in
- * {@code M}'s non-exported packages will be accessible.
- *
If the lookup for this {@code Lookup} is in a named module, and the
- * new lookup class is in a different module {@code M}, then no members, not even
- * public members in {@code M}'s exported packages, will be accessible.
- *
If the new lookup class differs from the old one,
- * protected members will not be accessible by virtue of inheritance.
- * (Protected members may continue to be accessible because of package sharing.)
+ *
If the old lookup class is in a {@link Module#isNamed() named} module, and
+ * the new lookup class is in a different module {@code M}, then no members, not
+ * even public members in {@code M}'s exported packages, will be accessible.
+ * The exception to this is when this lookup is {@link #publicLookup()
+ * publicLookup}, in which case {@code PUBLIC} access is not lost.
+ *
If the old lookup class is in an unnamed module, and the new lookup class
+ * is a different module then {@link #MODULE MODULE} access is lost.
+ *
If the new lookup class differs from the old one then {@code UNCONDITIONAL} is lost.
*
If the new lookup class is in a different package
* than the old one, protected and default (package) members will not be accessible.
*
If the new lookup class is not within the same package member
- * as the old one, private members will not be accessible.
+ * as the old one, private members will not be accessible, and protected members
+ * will not be accessible by virtue of inheritance.
+ * (Protected members may continue to be accessible because of package sharing.)
*
If the new lookup class is not accessible to the old lookup class,
* then no members, not even public members, will be accessible.
* (In all other cases, public members will continue to be accessible.)
@@ -757,32 +780,34 @@ public class MethodHandles {
* @return a lookup object which reports the desired lookup class, or the same object
* if there is no change
* @throws NullPointerException if the argument is null
+ *
+ * @revised 9
+ * @spec JPMS
*/
public Lookup in(Class> requestedLookupClass) {
Objects.requireNonNull(requestedLookupClass);
if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all
- return new Lookup(requestedLookupClass, ALL_MODES);
+ return new Lookup(requestedLookupClass, FULL_POWER_MODES);
if (requestedLookupClass == this.lookupClass)
return this; // keep same capabilities
-
- int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
+ int newModes = (allowedModes & FULL_POWER_MODES);
if (!VerifyAccess.isSameModule(this.lookupClass, requestedLookupClass)) {
- // Allowed to teleport from an unnamed to a named module but resulting
- // Lookup has no access to module private members
- if (this.lookupClass.getModule().isNamed()) {
+ // Need to drop all access when teleporting from a named module to another
+ // module. The exception is publicLookup where PUBLIC is not lost.
+ if (this.lookupClass.getModule().isNamed()
+ && (this.allowedModes & UNCONDITIONAL) == 0)
newModes = 0;
- } else {
- newModes &= ~MODULE;
- }
+ else
+ newModes &= ~(MODULE|PACKAGE|PRIVATE|PROTECTED);
}
if ((newModes & PACKAGE) != 0
&& !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
- newModes &= ~(PACKAGE|PRIVATE);
+ newModes &= ~(PACKAGE|PRIVATE|PROTECTED);
}
// Allow nestmate lookups to be created without special privilege:
if ((newModes & PRIVATE) != 0
&& !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
- newModes &= ~PRIVATE;
+ newModes &= ~(PRIVATE|PROTECTED);
}
if ((newModes & PUBLIC) != 0
&& !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) {
@@ -801,28 +826,29 @@ public class MethodHandles {
* finds members, but with a lookup mode that has lost the given lookup mode.
* The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
* MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
- * {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup
- * mode will never have this access capability. When dropping {@code PACKAGE}
- * then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE}
- * access. When dropping {@code MODULE} then the resulting lookup will not
- * have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code
- * PUBLIC} is dropped then the resulting lookup has no access.
+ * {@link #PROTECTED PROTECTED} and {@link #UNCONDITIONAL UNCONDITIONAL} are always
+ * dropped and so the resulting lookup mode will never have these access capabilities.
+ * When dropping {@code PACKAGE} then the resulting lookup will not have {@code PACKAGE}
+ * or {@code PRIVATE} access. When dropping {@code MODULE} then the resulting lookup will
+ * not have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code PUBLIC}
+ * is dropped then the resulting lookup has no access.
* @param modeToDrop the lookup mode to drop
* @return a lookup object which lacks the indicated mode, or the same object if there is no change
* @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
- * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE}
- * @since 9
+ * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED}, {@code PRIVATE} or {@code UNCONDITIONAL}
* @see MethodHandles#privateLookupIn
+ * @since 9
*/
public Lookup dropLookupMode(int modeToDrop) {
int oldModes = lookupModes();
- int newModes = oldModes & ~(modeToDrop | PROTECTED);
+ int newModes = oldModes & ~(modeToDrop | PROTECTED | UNCONDITIONAL);
switch (modeToDrop) {
case PUBLIC: newModes &= ~(ALL_MODES); break;
case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
case PACKAGE: newModes &= ~(PRIVATE); break;
case PROTECTED:
- case PRIVATE: break;
+ case PRIVATE:
+ case UNCONDITIONAL: break;
default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
}
if (newModes == oldModes) return this; // return self if no change
@@ -835,6 +861,12 @@ public class MethodHandles {
/** Package-private version of lookup which is trusted. */
static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
+ /** Version of lookup which is trusted minimally.
+ * It can only be used to create method handles to publicly accessible
+ * members in packages that are exported unconditionally.
+ */
+ static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, (PUBLIC|UNCONDITIONAL));
+
private static void checkUnprivilegedlookupClass(Class> lookupClass, int allowedModes) {
String name = lookupClass.getName();
if (name.startsWith("java.lang.invoke."))
@@ -845,7 +877,7 @@ public class MethodHandles {
// TODO replace with a more formal and less fragile mechanism
// that does not bluntly restrict classes under packages within
// java.base from looking up MethodHandles or VarHandles.
- if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) {
+ if (allowedModes == FULL_POWER_MODES && lookupClass.getClassLoader() == null) {
if ((name.startsWith("java.") &&
!name.equals("java.lang.Thread") &&
!name.startsWith("java.util.concurrent.")) ||
@@ -866,6 +898,7 @@ public class MethodHandles {
*
*
If no access is allowed, the suffix is "/noaccess".
*
If only public access to types in exported packages is allowed, the suffix is "/public".
+ *
If only public access and unconditional access are allowed, the suffix is "/publicLookup".
*
If only public and module access are allowed, the suffix is "/module".
*
If only public, module and package access are allowed, the suffix is "/package".
*
If only public, module, package, and private access are allowed, the suffix is "/private".
@@ -884,6 +917,9 @@ public class MethodHandles {
* because it requires a direct subclass relationship between
* caller and callee.)
* @see #in
+ *
+ * @revised 9
+ * @spec JPMS
*/
@Override
public String toString() {
@@ -893,13 +929,15 @@ public class MethodHandles {
return cname + "/noaccess";
case PUBLIC:
return cname + "/public";
+ case PUBLIC|UNCONDITIONAL:
+ return cname + "/publicLookup";
case PUBLIC|MODULE:
return cname + "/module";
case PUBLIC|MODULE|PACKAGE:
return cname + "/package";
- case ALL_MODES & ~PROTECTED:
+ case FULL_POWER_MODES & ~PROTECTED:
return cname + "/private";
- case ALL_MODES:
+ case FULL_POWER_MODES:
return cname;
case TRUSTED:
return "/trusted"; // internal only; not exported
@@ -1580,6 +1618,7 @@ return mh1;
if (refKind == REF_invokeSpecial)
refKind = REF_invokeVirtual;
assert(method.isMethod());
+ @SuppressWarnings("deprecation")
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
}
@@ -1662,6 +1701,7 @@ return mh1;
public MethodHandle unreflectConstructor(Constructor> c) throws IllegalAccessException {
MemberName ctor = new MemberName(c);
assert(ctor.isConstructor());
+ @SuppressWarnings("deprecation")
Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
}
@@ -1692,6 +1732,7 @@ return mh1;
assert(isSetter
? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
: MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
+ @SuppressWarnings("deprecation")
Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field);
}
@@ -2033,9 +2074,9 @@ return mh1;
(defc == refc ||
Modifier.isPublic(refc.getModifiers())));
if (!classOK && (allowedModes & PACKAGE) != 0) {
- classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) &&
+ classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), FULL_POWER_MODES) &&
(defc == refc ||
- VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES)));
+ VerifyAccess.isClassAccessible(refc, lookupClass(), FULL_POWER_MODES)));
}
if (!classOK)
return "class is not public";
@@ -2347,53 +2388,6 @@ return mh1;
static ConcurrentHashMap LOOKASIDE_TABLE = new ConcurrentHashMap<>();
}
- /**
- * Helper class used to lazily create PUBLIC_LOOKUP with a lookup class
- * in an unnamed module.
- *
- * @see Lookup#publicLookup
- */
- private static class LookupHelper {
- private static final String UNNAMED = "Unnamed";
- private static final String OBJECT = "java/lang/Object";
-
- private static Class> createClass() {
- try {
- ClassWriter cw = new ClassWriter(0);
- cw.visit(Opcodes.V1_8,
- Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
- UNNAMED,
- null,
- OBJECT,
- null);
- cw.visitSource(UNNAMED, null);
- cw.visitEnd();
- byte[] bytes = cw.toByteArray();
- ClassLoader loader = new ClassLoader(null) {
- @Override
- protected Class> findClass(String cn) throws ClassNotFoundException {
- if (cn.equals(UNNAMED))
- return super.defineClass(UNNAMED, bytes, 0, bytes.length);
- throw new ClassNotFoundException(cn);
- }
- };
- return loader.loadClass(UNNAMED);
- } catch (Exception e) {
- throw new InternalError(e);
- }
- }
-
- private static final Class> PUBLIC_LOOKUP_CLASS = createClass();
-
- /**
- * Lookup that is trusted minimally. It can only be used to create
- * method handles to publicly accessible members in exported packages.
- *
- * @see MethodHandles#publicLookup
- */
- static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_LOOKUP_CLASS, Lookup.PUBLIC);
- }
-
/**
* Produces a method handle constructing arrays of a desired type.
* The return type of the method handle will be the array type.
diff --git a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java
index 9753569374d..6203b1277ff 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,126 +42,48 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
- * The configuration that is the result of resolution or resolution with
- * service binding.
+ * A configuration that is the result of
+ * resolution or resolution with
+ * service binding.
*
- *
A configuration encapsulates the readability graph that is the
+ * output of resolution. A readability graph is a directed graph where the nodes
+ * are of type {@link ResolvedModule} and the edges represent the readability
+ * amongst the modules. {@code Configuration} defines the {@link #modules()
+ * modules()} method to get the set of resolved modules in the graph. {@code
+ * ResolvedModule} defines the {@link ResolvedModule#reads() reads()} method to
+ * get the set of modules that a resolved module reads. The modules that are
+ * read may be in the same configuration or may be in {@link #parents() parent}
+ * configurations.
*
- *
Resolution is the process of computing the transitive closure of a set
- * of root modules over a set of observable modules by resolving the
- * dependences expressed by {@code requires} clauses.
+ *
Configuration defines the {@link #resolve(ModuleFinder,List,ModuleFinder,Collection)
+ * resolve} method to resolve a collection of root modules, and the {@link
+ * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) resolveAndBind}
+ * method to do resolution with service binding. There are instance and
+ * static variants of both methods. The instance methods create a configuration
+ * with the receiver as the parent configuration. The static methods are for
+ * more advanced cases where there can be more than one parent configuration.
*
- * The dependence graph is augmented with edges that take account of
- * implicitly declared dependences ({@code requires transitive}) to create a
- * readability graph. A {@code Configuration} encapsulates the
- * resulting graph of {@link ResolvedModule resolved modules}.
- *
- *
If the module {@code m1} is resolved then the resulting configuration
- * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in
- * its readability graph are:
Resolution is an additive process. When computing the transitive closure
- * then the dependence relation may include dependences on modules in parent
- * configurations. The result is a relative configuration that is
- * relative to one or more parent configurations and where the readability graph
- * may have edges from modules in the configuration to modules in parent
- * configurations.
- *
- *
If module {@code m1} is resolved with the configuration for the {@link
- * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting
- * configuration contains two modules ({@code m1}, {@code m2}). The edges in
- * its readability graph are:
- *
{@code
- * m1 --> m2
- * m1 --> java.xml
- * }
- * where module {@code java.xml} is in the parent configuration. For
- * simplicity, this example omits the implicitly declared dependence on the
- * {@code java.base} module.
- *
- *
- *
{@link ModuleDescriptor#isAutomatic() Automatic} modules receive special
- * treatment during resolution. Each automatic module is resolved so that it
- * reads all other modules in the configuration and all parent configurations.
- * Each automatic module is also resolved as if it {@code requires transitive}
- * all other automatic modules in the configuration (and all automatic modules
- * in parent configurations).
Service binding is the process of augmenting a graph of resolved modules
- * from the set of observable modules induced by the service-use dependence
- * ({@code uses} and {@code provides} clauses). Any module that was not
- * previously in the graph requires resolution to compute its transitive
- * closure. Service binding is an iterative process in that adding a module
- * that satisfies some service-use dependence may introduce new service-use
- * dependences.
If the module {@code m1} is resolved then the resulting graph of modules
- * has one module ({@code m1}). If the graph is augmented with modules induced
- * by the service-use dependence relation then the configuration will contain
- * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in
- * its readability graph are:
The edges in the conceptual service-use graph are:
- *
{@code
- * m1 --> m2 (meaning m1 uses a service that is provided by m2)
- * m1 --> m3
- * }
- *
- *
If this configuration is instantiated as a {@code Layer}, and if code in
- * module {@code m1} uses {@link java.util.ServiceLoader ServiceLoader} to
- * iterate over implementations of {@code p.S.class}, then it will iterate over
- * an instance of {@code p2.S2} and {@code p3.S3}.
+ *
Each {@link java.lang.reflect.Layer layer} of modules in the Java virtual
+ * machine is created from a configuration. The configuration for the {@link
+ * java.lang.reflect.Layer#boot() boot} layer is obtained by invoking {@code
+ * Layer.boot().configuration()}. The configuration for the boot layer will
+ * often be the parent when creating new configurations.
*
*
Example
*
- *
The following example uses the {@code resolveRequires} method to resolve
- * a module named myapp with the configuration for the boot layer as
- * the parent configuration. It prints the name of each resolved module and
- * the names of the modules that each module reads.
+ *
The following example uses the {@link
+ * #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a
+ * module named myapp with the configuration for the boot layer as the
+ * parent configuration. It prints the name of each resolved module and the
+ * names of the modules that each module reads.
*
* @since 9
+ * @spec JPMS
* @see java.lang.reflect.Layer
*/
public final class Configuration {
@@ -186,11 +109,23 @@ public final class Configuration {
private final Set modules;
private final Map nameToModule;
+ // module constraints on target
+ private final String osName;
+ private final String osArch;
+ private final String osVersion;
+
+ String osName() { return osName; }
+ String osArch() { return osArch; }
+ String osVersion() { return osVersion; }
+
private Configuration() {
this.parents = Collections.emptyList();
this.graph = Collections.emptyMap();
this.modules = Collections.emptySet();
this.nameToModule = Collections.emptyMap();
+ this.osName = null;
+ this.osArch = null;
+ this.osVersion = null;
}
private Configuration(List parents,
@@ -214,27 +149,30 @@ public final class Configuration {
this.graph = g;
this.modules = Set.of(moduleArray);
this.nameToModule = Map.ofEntries(nameEntries);
- }
+ this.osName = resolver.osName();
+ this.osArch = resolver.osArch();
+ this.osVersion = resolver.osVersion();
+ }
/**
* Resolves a collection of root modules, with this configuration as its
* parent, to create a new configuration. This method works exactly as
* specified by the static {@link
- * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires}
+ * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve}
* method when invoked with this configuration as the parent. In other words,
* if this configuration is {@code cf} then this method is equivalent to
* invoking:
*
*
* @param before
* The before module finder to find modules
* @param after
- * The after module finder to locate modules when a
- * module cannot be located by the {@code before} module finder
- * and the module is not in this configuration
+ * The after module finder to locate modules when not
+ * located by the {@code before} module finder or in parent
+ * configurations
* @param roots
* The possibly-empty collection of module names of the modules
* to resolve
@@ -242,16 +180,20 @@ public final class Configuration {
* @return The configuration that is the result of resolving the given
* root modules
*
+ * @throws FindException
+ * If resolution fails for any of the observability-related reasons
+ * specified by the static {@code resolve} method
* @throws ResolutionException
- * If resolution or the post-resolution checks fail
+ * If any of the post-resolution consistency checks specified by
+ * the static {@code resolve} method fail
* @throws SecurityException
* If locating a module is denied by the security manager
*/
- public Configuration resolveRequires(ModuleFinder before,
- ModuleFinder after,
- Collection roots)
+ public Configuration resolve(ModuleFinder before,
+ ModuleFinder after,
+ Collection roots)
{
- return resolveRequires(before, List.of(this), after, roots);
+ return resolve(before, List.of(this), after, roots);
}
@@ -259,12 +201,12 @@ public final class Configuration {
* Resolves a collection of root modules, with service binding, and with
* this configuration as its parent, to create a new configuration.
* This method works exactly as specified by the static {@link
- * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection)
- * resolveRequiresAndUses} method when invoked with this configuration
+ * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection)
+ * resolveAndBind} method when invoked with this configuration
* as the parent. In other words, if this configuration is {@code cf} then
* this method is equivalent to invoking:
*
*
*
@@ -272,25 +214,29 @@ public final class Configuration {
* The before module finder to find modules
* @param after
* The after module finder to locate modules when not
- * located by the {@code before} module finder and this
- * configuration
+ * located by the {@code before} module finder or in parent
+ * configurations
* @param roots
* The possibly-empty collection of module names of the modules
* to resolve
*
- * @return The configuration that is the result of resolving the given
- * root modules
+ * @return The configuration that is the result of resolving, with service
+ * binding, the given root modules
*
+ * @throws FindException
+ * If resolution fails for any of the observability-related reasons
+ * specified by the static {@code resolve} method
* @throws ResolutionException
- * If resolution or the post-resolution checks fail
+ * If any of the post-resolution consistency checks specified by
+ * the static {@code resolve} method fail
* @throws SecurityException
* If locating a module is denied by the security manager
*/
- public Configuration resolveRequiresAndUses(ModuleFinder before,
- ModuleFinder after,
- Collection roots)
+ public Configuration resolveAndBind(ModuleFinder before,
+ ModuleFinder after,
+ Collection roots)
{
- return resolveRequiresAndUses(before, List.of(this), after, roots);
+ return resolveAndBind(before, List.of(this), after, roots);
}
@@ -301,14 +247,14 @@ public final class Configuration {
*
* This method is used to create the configuration for the boot layer.
*/
- static Configuration resolveRequiresAndUses(ModuleFinder finder,
- Collection roots,
- boolean check,
- PrintStream traceOutput)
+ static Configuration resolveAndBind(ModuleFinder finder,
+ Collection roots,
+ boolean check,
+ PrintStream traceOutput)
{
List parents = List.of(empty());
Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
- resolver.resolveRequires(roots).resolveUses();
+ resolver.resolve(roots).bind();
return new Configuration(parents, resolver, check);
}
@@ -328,11 +274,11 @@ public final class Configuration {
*
*
When all modules have been resolved then the resulting dependency
* graph is checked to ensure that it does not contain cycles. A
- * readability graph is constructed and in conjunction with the module
+ * readability graph is constructed, and in conjunction with the module
* exports and service use, checked for consistency.
*
- *
Resolution and the (post-resolution) consistency checks may fail for
- * following reasons:
+ *
Resolution may fail with {@code FindException} for the following
+ * observability-related reasons:
*
*
*
A root module, or a direct or transitive dependency, is not
@@ -343,6 +289,20 @@ public final class Configuration {
* descriptor ({@code module-info.class}) or two versions of the same
* module are found in the same directory.
*
+ *
A module with the required name is found but the module
+ * requires a different {@link ModuleDescriptor#osName() operating
+ * system}, {@link ModuleDescriptor#osArch() architecture}, or {@link
+ * ModuleDescriptor#osVersion() version} to other modules that have
+ * been resolved for the new configuration or modules in the parent
+ * configurations.
+ *
+ *
+ *
+ *
Post-resolution consistency checks may fail with {@code
+ * ResolutionException} for the following reasons:
+ *
+ *
+ *
*
A cycle is detected, say where module {@code m1} requires
* module {@code m2} and {@code m2} requires {@code m1}.
*
@@ -356,21 +316,12 @@ public final class Configuration {
* module {@code M} nor exported to {@code M} by any module that
* {@code M} reads.
*
- *
A module {@code M} declares that it
- * "{@code provides ... with q.T}" but package {@code q} is not in
- * module {@code M}.
- *
- *
Two or more modules in the configuration are specific to
- * different {@link ModuleDescriptor#osName() operating systems},
- * {@link ModuleDescriptor#osArch() architectures}, or {@link
- * ModuleDescriptor#osVersion() versions}.
- *
- *
Other implementation specific checks, for example referential
- * integrity checks to ensure that different versions of tighly coupled
- * modules cannot be combined in the same configuration.
- *
*
*
+ * @implNote In the implementation then observability of modules may depend
+ * on referential integrity checks that ensure different builds of tightly
+ * coupled modules are not combined in the same configuration.
+ *
* @param before
* The before module finder to find modules
* @param parents
@@ -386,17 +337,22 @@ public final class Configuration {
* @return The configuration that is the result of resolving the given
* root modules
*
+ * @throws FindException
+ * If resolution fails for an observability-related reason
* @throws ResolutionException
- * If resolution or the post-resolution checks fail
+ * If a post-resolution consistency checks fails
* @throws IllegalArgumentException
- * If the list of parents is empty
+ * If the list of parents is empty, or the list has two or more
+ * parents with modules for different target operating systems,
+ * architectures, or versions
+ *
* @throws SecurityException
* If locating a module is denied by the security manager
*/
- public static Configuration resolveRequires(ModuleFinder before,
- List parents,
- ModuleFinder after,
- Collection roots)
+ public static Configuration resolve(ModuleFinder before,
+ List parents,
+ ModuleFinder after,
+ Collection roots)
{
Objects.requireNonNull(before);
Objects.requireNonNull(after);
@@ -407,7 +363,7 @@ public final class Configuration {
throw new IllegalArgumentException("'parents' is empty");
Resolver resolver = new Resolver(before, parentList, after, null);
- resolver.resolveRequires(roots);
+ resolver.resolve(roots);
return new Configuration(parentList, resolver, true);
}
@@ -417,24 +373,24 @@ public final class Configuration {
* configuration.
*
*
This method works exactly as specified by {@link
- * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection)
- * resolveRequires} except that the graph of resolved modules is augmented
+ * #resolve(ModuleFinder,List,ModuleFinder,Collection)
+ * resolve} except that the graph of resolved modules is augmented
* with modules induced by the service-use dependence relation.
*
*
More specifically, the root modules are resolved as if by calling
- * {@code resolveRequires}. The resolved modules, and all modules in the
+ * {@code resolve}. The resolved modules, and all modules in the
* parent configurations, with {@link ModuleDescriptor#uses() service
* dependences} are then examined. All modules found by the given module
* finders that {@link ModuleDescriptor#provides() provide} an
* implementation of one or more of the service types are added to the
* module graph and then resolved as if by calling the {@code
- * resolveRequires} method. Adding modules to the module graph may
- * introduce new service-use dependences and so the process works
- * iteratively until no more modules are added.
+ * resolve} method. Adding modules to the module graph may introduce new
+ * service-use dependences and so the process works iteratively until no
+ * more modules are added.
*
- *
As service binding involves resolution then it may fail with {@link
- * ResolutionException} for exactly the same reasons specified in
- * {@code resolveRequires}.
+ *
As service binding involves resolution then it may fail with {@code
+ * FindException} or {@code ResolutionException} for exactly the same
+ * reasons specified in {@code resolve}.
*
* @param before
* The before module finder to find modules
@@ -448,20 +404,26 @@ public final class Configuration {
* The possibly-empty collection of module names of the modules
* to resolve
*
- * @return The configuration that is the result of resolving the given
- * root modules
+ * @return The configuration that is the result of resolving, with service
+ * binding, the given root modules
*
+ * @throws FindException
+ * If resolution fails for any of the observability-related reasons
+ * specified by the static {@code resolve} method
* @throws ResolutionException
- * If resolution or the post-resolution checks fail
+ * If any of the post-resolution consistency checks specified by
+ * the static {@code resolve} method fail
* @throws IllegalArgumentException
- * If the list of parents is empty
+ * If the list of parents is empty, or the list has two or more
+ * parents with modules for different target operating systems,
+ * architectures, or versions
* @throws SecurityException
* If locating a module is denied by the security manager
*/
- public static Configuration resolveRequiresAndUses(ModuleFinder before,
- List parents,
- ModuleFinder after,
- Collection roots)
+ public static Configuration resolveAndBind(ModuleFinder before,
+ List parents,
+ ModuleFinder after,
+ Collection roots)
{
Objects.requireNonNull(before);
Objects.requireNonNull(after);
@@ -472,7 +434,7 @@ public final class Configuration {
throw new IllegalArgumentException("'parents' is empty");
Resolver resolver = new Resolver(before, parentList, after, null);
- resolver.resolveRequires(roots).resolveUses();
+ resolver.resolve(roots).bind();
return new Configuration(parentList, resolver, true);
}
diff --git a/jdk/src/java.base/share/classes/java/lang/module/FindException.java b/jdk/src/java.base/share/classes/java/lang/module/FindException.java
index d76f2935e7e..411959eb418 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/FindException.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/FindException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,14 @@
package java.lang.module;
/**
- * Thrown by module finders when finding a module fails.
+ * Thrown by a {@link ModuleFinder ModuleFinder} when an error occurs finding
+ * a module. Also thrown by {@link
+ * Configuration#resolve(ModuleFinder,java.util.List,ModuleFinder,java.util.Collection)
+ * Configuration.resolve} when resolution fails for observability-related
+ * reasons.
*
- * @see ModuleFinder
* @since 9
+ * @spec JPMS
*/
public class FindException extends RuntimeException {
diff --git a/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java b/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java
index 981f23a5189..3e306886fb2 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java
@@ -31,6 +31,7 @@ package java.lang.module;
*
* @see ModuleDescriptor#read
* @since 9
+ * @spec JPMS
*/
public class InvalidModuleDescriptorException extends RuntimeException {
private static final long serialVersionUID = 4863390386809347380L;
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
index b10d986ade9..6c05e821026 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@ import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
@@ -56,29 +57,83 @@ import jdk.internal.module.ModuleInfo;
/**
* A module descriptor.
*
- *
A {@code ModuleDescriptor} is typically created from the binary form
- * of a module declaration. Alternatively, the {@link ModuleDescriptor.Builder}
- * class can be used to create a {@code ModuleDescriptor} from its components.
- * The {@link #module module}, {@link #openModule openModule}, and {@link
- * #automaticModule automaticModule} methods create builders for building
- * different kinds of modules.
+ *
A module descriptor describes a named module and defines methods to
+ * obtain each of its components. The module descriptor for a named module
+ * in the Java virtual machine is obtained by invoking the {@link
+ * java.lang.reflect.Module Module}'s {@link java.lang.reflect.Module#getDescriptor
+ * getDescriptor} method. Module descriptors can also be created using the
+ * {@link ModuleDescriptor.Builder} class or by reading the binary form of a
+ * module declaration ({@code module-info.class}) using the {@link
+ * #read(InputStream,Supplier) read} methods defined here.
+ *
+ *
A module descriptor describes a normal, open, or automatic
+ * module. Normal modules and open modules describe their {@link
+ * #requires() dependences}, {@link #exports() exported-packages}, the services
+ * that they {@link #uses() use} or {@link #provides() provide}, and other
+ * components. Normal modules may {@link #opens() open} specific
+ * packages. The module descriptor for an open modules does not declare any
+ * open packages (its {@code opens} method returns an empty set) but when
+ * instantiated in the Java virtual machine then it is treated as if all
+ * packages are open. The module descriptor for an automatic module does not
+ * declare any dependences (except for the mandatory dependency on {@code
+ * java.base}), and does not declare any exported or open packages. Automatic
+ * module receive special treatment during resolution so that they read all
+ * other modules in the configuration. When an automatic module is instantiated
+ * in the Java virtual machine then it reads every unnamed module and is
+ * treated as if all packages are exported and open.
*
*
{@code ModuleDescriptor} objects are immutable and safe for use by
* multiple concurrent threads.
*
- * @since 9
* @see java.lang.reflect.Module
+ * @since 9
+ * @spec JPMS
*/
public class ModuleDescriptor
implements Comparable
{
+ /**
+ * A modifier on a module.
+ *
+ * @see ModuleDescriptor#modifiers()
+ * @since 9
+ */
+ public static enum Modifier {
+ /**
+ * An open module. An open module does not declare any open packages
+ * but the resulting module is treated as if all packages are open.
+ */
+ OPEN,
+
+ /**
+ * An automatic module. An automatic module is treated as if it exports
+ * and opens all packages.
+ *
+ * @apiNote This modifier does not correspond to a module flag in the
+ * binary form of a module declaration ({@code module-info.class}).
+ */
+ AUTOMATIC,
+
+ /**
+ * The module was not explicitly or implicitly declared.
+ */
+ SYNTHETIC,
+
+ /**
+ * The module was implicitly declared.
+ */
+ MANDATED;
+ }
+
+
/**
*
A dependence upon a module
*
* @see ModuleDescriptor#requires()
* @since 9
+ * @spec JPMS
*/
public final static class Requires
@@ -88,7 +143,9 @@ public class ModuleDescriptor
/**
* A modifier on a module dependence.
*
+ * @see Requires#modifiers()
* @since 9
+ * @spec JPMS
*/
public static enum Modifier {
@@ -171,14 +228,18 @@ public class ModuleDescriptor
* Compares this module dependence to another.
*
*
Two {@code Requires} objects are compared by comparing their
- * module name lexicographically. Where the module names are equal then
- * the sets of modifiers are compared based on a value computed from the
- * ordinal of each modifier. Where the module names are equal and the
- * set of modifiers are equal then the version of the modules recorded
- * at compile-time are compared. When comparing the versions recorded
- * at compile-time then a dependence that has a recorded version is
- * considered to succeed a dependence that does not have a recorded
- * version.
+ * module names lexicographically. Where the module names are equal
+ * then the sets of modifiers are compared in the same way that
+ * module modifiers are compared (see {@link ModuleDescriptor#compareTo
+ * ModuleDescriptor.compareTo}). Where the module names are equal and
+ * the set of modifiers are equal then the version of the modules
+ * recorded at compile-time are compared. When comparing the versions
+ * recorded at compile-time then a dependence that has a recorded
+ * version is considered to succeed a dependence that does not have a
+ * recorded version.
+ *
+ * @param that
+ * The module dependence to compare
*
* @return A negative integer, zero, or a positive integer if this module
* dependence is less than, equal to, or greater than the given
@@ -186,39 +247,22 @@ public class ModuleDescriptor
*/
@Override
public int compareTo(Requires that) {
+ if (this == that) return 0;
+
int c = this.name().compareTo(that.name());
- if (c != 0)
- return c;
+ if (c != 0) return c;
// modifiers
- c = Long.compare(this.modsValue(), that.modsValue());
- if (c != 0)
- return c;
+ long v1 = modsValue(this.modifiers());
+ long v2 = modsValue(that.modifiers());
+ c = Long.compare(v1, v2);
+ if (c != 0) return c;
// compiledVersion
- if (this.compiledVersion != null) {
- if (that.compiledVersion != null)
- c = this.compiledVersion.compareTo(that.compiledVersion);
- else
- c = 1;
- } else {
- if (that.compiledVersion != null)
- c = -1;
- }
+ c = compare(this.compiledVersion, that.compiledVersion);
+ if (c != 0) return c;
- return c;
- }
-
- /**
- * Return a value for the modifiers to allow sets of modifiers to be
- * compared.
- */
- private long modsValue() {
- long value = 0;
- for (Modifier m : mods) {
- value += 1 << m.ordinal();
- }
- return value;
+ return 0;
}
/**
@@ -266,9 +310,9 @@ public class ModuleDescriptor
}
/**
- * Returns a string describing module dependence.
+ * Returns a string describing this module dependence.
*
- * @return A string describing module dependence
+ * @return A string describing this module dependence
*/
@Override
public String toString() {
@@ -285,18 +329,23 @@ public class ModuleDescriptor
/**
- *
A module export, may be qualified or unqualified.
+ *
A package exported by a module, may be qualified or unqualified.
*
* @see ModuleDescriptor#exports()
* @since 9
+ * @spec JPMS
*/
- public final static class Exports {
+ public final static class Exports
+ implements Comparable
+ {
/**
- * A modifier on a module export.
+ * A modifier on an exported package.
*
+ * @see Exports#modifiers()
* @since 9
+ * @spec JPMS
*/
public static enum Modifier {
@@ -380,6 +429,52 @@ public class ModuleDescriptor
return targets;
}
+ /**
+ * Compares this module export to another.
+ *
+ *
Two {@code Exports} objects are compared by comparing the package
+ * names lexicographically. Where the packages names are equal then the
+ * sets of modifiers are compared in the same way that module modifiers
+ * are compared (see {@link ModuleDescriptor#compareTo
+ * ModuleDescriptor.compareTo}). Where the package names are equal and
+ * the set of modifiers are equal then the set of target modules are
+ * compared. This is done by sorting the names of the target modules
+ * in ascending order, and according to their natural ordering, and then
+ * comparing the corresponding elements lexicographically. Where the
+ * sets differ in size, and the larger set contains all elements of the
+ * smaller set, then the larger set is considered to succeed the smaller
+ * set.
+ *
+ * @param that
+ * The module export to compare
+ *
+ * @return A negative integer, zero, or a positive integer if this module
+ * export is less than, equal to, or greater than the given
+ * export dependence
+ */
+ @Override
+ public int compareTo(Exports that) {
+ if (this == that) return 0;
+
+ int c = source.compareTo(that.source);
+ if (c != 0)
+ return c;
+
+ // modifiers
+ long v1 = modsValue(this.modifiers());
+ long v2 = modsValue(that.modifiers());
+ c = Long.compare(v1, v2);
+ if (c != 0)
+ return c;
+
+ // targets
+ c = compare(targets, that.targets);
+ if (c != 0)
+ return c;
+
+ return 0;
+ }
+
/**
* Computes a hash code for this module export.
*
@@ -425,9 +520,9 @@ public class ModuleDescriptor
}
/**
- * Returns a string describing module export.
+ * Returns a string describing the exported package.
*
- * @return A string describing module export
+ * @return A string describing the exported package
*/
@Override
public String toString() {
@@ -441,8 +536,7 @@ public class ModuleDescriptor
/**
- *
Represents a module opens directive, may be qualified or
- * unqualified.
+ *
A package opened by a module, may be qualified or unqualified.
*
*
The opens directive in a module declaration declares a
* package to be open to allow all types in the package, and all their
@@ -452,26 +546,30 @@ public class ModuleDescriptor
*
* @see ModuleDescriptor#opens()
* @since 9
+ * @spec JPMS
*/
- public final static class Opens {
-
+ public final static class Opens
+ implements Comparable
+ {
/**
- * A modifier on a module opens directive.
+ * A modifier on an open package.
*
+ * @see Opens#modifiers()
* @since 9
+ * @spec JPMS
*/
public static enum Modifier {
/**
- * The opens was not explicitly or implicitly declared in the
- * source of the module declaration.
+ * The open package was not explicitly or implicitly declared in
+ * the source of the module declaration.
*/
SYNTHETIC,
/**
- * The opens was implicitly declared in the source of the module
- * declaration.
+ * The open package was implicitly declared in the source of the
+ * module declaration.
*/
MANDATED;
@@ -543,6 +641,52 @@ public class ModuleDescriptor
return targets;
}
+ /**
+ * Compares this module opens to another.
+ *
+ *
Two {@code Opens} objects are compared by comparing the package
+ * names lexicographically. Where the packages names are equal then the
+ * sets of modifiers are compared in the same way that module modifiers
+ * are compared (see {@link ModuleDescriptor#compareTo
+ * ModuleDescriptor.compareTo}). Where the package names are equal and
+ * the set of modifiers are equal then the set of target modules are
+ * compared. This is done by sorting the names of the target modules
+ * in ascending order, and according to their natural ordering, and then
+ * comparing the corresponding elements lexicographically. Where the
+ * sets differ in size, and the larger set contains all elements of the
+ * smaller set, then the larger set is considered to succeed the smaller
+ * set.
+ *
+ * @param that
+ * The module opens to compare
+ *
+ * @return A negative integer, zero, or a positive integer if this module
+ * opens is less than, equal to, or greater than the given
+ * module opens
+ */
+ @Override
+ public int compareTo(Opens that) {
+ if (this == that) return 0;
+
+ int c = source.compareTo(that.source);
+ if (c != 0)
+ return c;
+
+ // modifiers
+ long v1 = modsValue(this.modifiers());
+ long v2 = modsValue(that.modifiers());
+ c = Long.compare(v1, v2);
+ if (c != 0)
+ return c;
+
+ // targets
+ c = compare(targets, that.targets);
+ if (c != 0)
+ return c;
+
+ return 0;
+ }
+
/**
* Computes a hash code for this module opens.
*
@@ -588,9 +732,9 @@ public class ModuleDescriptor
}
/**
- * Returns a string describing module opens.
+ * Returns a string describing the open package.
*
- * @return A string describing module opens
+ * @return A string describing the open package
*/
@Override
public String toString() {
@@ -608,10 +752,12 @@ public class ModuleDescriptor
*
* @see ModuleDescriptor#provides()
* @since 9
+ * @spec JPMS
*/
- public final static class Provides {
-
+ public final static class Provides
+ implements Comparable
+ {
private final String service;
private final List providers;
@@ -641,6 +787,46 @@ public class ModuleDescriptor
*/
public List providers() { return providers; }
+ /**
+ * Compares this provides to another.
+ *
+ *
Two {@code Provides} objects are compared by comparing the fully
+ * qualified class name of the service type lexicographically. Where the
+ * class names are equal then the list of the provider class names are
+ * compared by comparing the corresponding elements of both lists
+ * lexicographically and in sequence. Where the lists differ in size,
+ * {@code N} is the size of the shorter list, and the first {@code N}
+ * corresponding elements are equal, then the longer list is considered
+ * to succeed the shorter list.
+ *
+ * @param that
+ * The {@code Provides} to compare
+ *
+ * @return A negative integer, zero, or a positive integer if this provides
+ * is less than, equal to, or greater than the given provides
+ */
+ public int compareTo(Provides that) {
+ if (this == that) return 0;
+
+ int c = service.compareTo(that.service);
+ if (c != 0) return c;
+
+ // compare provider class names in sequence
+ int size1 = this.providers.size();
+ int size2 = that.providers.size();
+ for (int index=0; index size2) ? 1 : -1;
+ }
+ }
+
/**
* Computes a hash code for this provides.
*
@@ -699,7 +885,7 @@ public class ModuleDescriptor
*
*
A version string has three components: The version number itself, an
* optional pre-release version, and an optional build version. Each
- * component is sequence of tokens; each token is either a non-negative
+ * component is a sequence of tokens; each token is either a non-negative
* integer or a string. Tokens are separated by the punctuation characters
* {@code '.'}, {@code '-'}, or {@code '+'}, or by transitions from a
* sequence of digits to a sequence of characters that are neither digits
@@ -740,6 +926,7 @@ public class ModuleDescriptor
*
* @see ModuleDescriptor#version()
* @since 9
+ * @spec JPMS
*/
public final static class Version
@@ -1009,36 +1196,26 @@ public class ModuleDescriptor
}
-
+
private final String name;
private final Version version;
- private final boolean open;
-
- // Indicates if synthesised for a JAR file found on the module path
- private final boolean automatic;
-
- // Not generated from a module-info.java
- private final boolean synthetic;
-
+ private final Set modifiers;
+ private final boolean open; // true if modifiers contains OPEN
+ private final boolean automatic; // true if modifiers contains AUTOMATIC
private final Set requires;
private final Set exports;
private final Set opens;
private final Set uses;
private final Set provides;
-
- // Added post-compilation by tools
private final Set packages;
private final String mainClass;
private final String osName;
private final String osArch;
private final String osVersion;
-
private ModuleDescriptor(String name,
Version version,
- boolean open,
- boolean automatic,
- boolean synthetic,
+ Set modifiers,
Set requires,
Set exports,
Set opens,
@@ -1052,10 +1229,9 @@ public class ModuleDescriptor
{
this.name = name;
this.version = version;
- this.open = open;
- this.automatic = automatic;
- this.synthetic = synthetic;
-
+ this.modifiers = emptyOrUnmodifiableSet(modifiers);
+ this.open = modifiers.contains(Modifier.OPEN);
+ this.automatic = modifiers.contains(Modifier.AUTOMATIC);
assert (requires.stream().map(Requires::name).distinct().count()
== requires.size());
this.requires = emptyOrUnmodifiableSet(requires);
@@ -1071,41 +1247,13 @@ public class ModuleDescriptor
this.osVersion = osVersion;
}
- /**
- * Clones the given module descriptor with an augmented set of packages
- */
- ModuleDescriptor(ModuleDescriptor md, Set pkgs) {
- this.name = md.name;
- this.version = md.version;
- this.open = md.open;
- this.automatic = md.automatic;
- this.synthetic = md.synthetic;
-
- this.requires = md.requires;
- this.exports = md.exports;
- this.opens = md.opens;
- this.uses = md.uses;
- this.provides = md.provides;
-
- Set packages = new HashSet<>(md.packages);
- packages.addAll(pkgs);
- this.packages = emptyOrUnmodifiableSet(packages);
-
- this.mainClass = md.mainClass;
- this.osName = md.osName;
- this.osArch = md.osArch;
- this.osVersion = md.osVersion;
- }
-
/**
* Creates a module descriptor from its components.
* The arguments are pre-validated and sets are unmodifiable sets.
*/
ModuleDescriptor(String name,
Version version,
- boolean open,
- boolean automatic,
- boolean synthetic,
+ Set modifiers,
Set requires,
Set exports,
Set opens,
@@ -1120,9 +1268,9 @@ public class ModuleDescriptor
boolean unused) {
this.name = name;
this.version = version;
- this.open = open;
- this.automatic = automatic;
- this.synthetic = synthetic;
+ this.modifiers = modifiers;
+ this.open = modifiers.contains(Modifier.OPEN);
+ this.automatic = modifiers.contains(Modifier.AUTOMATIC);
this.requires = requires;
this.exports = exports;
this.opens = opens;
@@ -1137,7 +1285,7 @@ public class ModuleDescriptor
}
/**
- *
The module name.
+ *
Returns the module name.
*
* @return The module name
*/
@@ -1145,12 +1293,20 @@ public class ModuleDescriptor
return name;
}
+ /**
+ *
Returns the set of module modifiers.
+ *
+ * @return A possibly-empty unmodifiable set of modifiers
+ */
+ public Set modifiers() {
+ return modifiers;
+ }
+
/**
*
Returns {@code true} if this is an open module.
*
- *
An open module does not declare any open packages (the {@link #opens()
- * opens} method returns an empty set) but the resulting module is treated
- * as if all packages are open.
+ *
This method is equivalent to testing if the set of {@link #modifiers
+ * modifiers} contains the {@link Modifier#OPEN OPEN} modifier.
*
* @return {@code true} if this is an open module
*/
@@ -1161,12 +1317,8 @@ public class ModuleDescriptor
/**
*
Returns {@code true} if this is an automatic module.
*
- *
An automatic module is defined implicitly rather than explicitly
- * and therefore does not have a module declaration. JAR files located on
- * the application module path, or by the {@link ModuleFinder} returned by
- * {@link ModuleFinder#of(java.nio.file.Path[]) ModuleFinder.of}, are
- * treated as automatic modules if they do have not have a module
- * declaration.
+ *
This method is equivalent to testing if the set of {@link #modifiers
+ * modifiers} contains the {@link Modifier#OPEN AUTOMATIC} modifier.
*
* @return {@code true} if this is an automatic module
*/
@@ -1175,20 +1327,13 @@ public class ModuleDescriptor
}
/**
- *
Returns {@code true} if this module descriptor was not generated
- * from an explicit module declaration ({@code module-info.java})
- * or an implicit module declaration (an {@link #isAutomatic() automatic}
- * module).
+ *
Returns the set of {@code Requires} objects representing the module
+ * dependences.
*
- * @return {@code true} if this module descriptor was not generated by
- * an explicit or implicit module declaration
- */
- public boolean isSynthetic() {
- return synthetic;
- }
-
- /**
- *
The dependences of this module.
+ *
The set includes a dependency on "{@code java.base}" when this
+ * module is not named "{@code java.base}". If this module is an automatic
+ * module then it does not have a dependency on any module other than
+ * "{@code java.base}".
*
* @return A possibly-empty unmodifiable set of {@link Requires} objects
*/
@@ -1197,7 +1342,11 @@ public class ModuleDescriptor
}
/**
- *
The module exports.
+ *
Returns the set of {@code Exports} objects representing the exported
+ * packages.
+ *
+ *
If this module is an automatic module then the set of exports
+ * is empty.
*
* @return A possibly-empty unmodifiable set of exported packages
*/
@@ -1206,16 +1355,11 @@ public class ModuleDescriptor
}
/**
- *
The module opens directives.
+ *
Returns the set of {@code Opens} objects representing the open
+ * packages.
*
- *
Each {@code Opens} object in the set represents a package (and
- * the set of target module names when qualified) where all types in the
- * package, and all their members, not just public types and their public
- * members, can be reflected on when using APIs that bypass or suppress
- * default Java language access control checks.
- *
- *
This method returns an empty set when invoked on {@link #isOpen()
- * open} module.
+ *
If this module is an open module or an automatic module then the
+ * set of open packages is empty.
*
* @return A possibly-empty unmodifiable set of open packages
*/
@@ -1224,7 +1368,10 @@ public class ModuleDescriptor
}
/**
- *
The service dependences of this module.
+ *
Returns the set of service dependences.
+ *
+ *
If this module is an automatic module then the set of service
+ * dependences is empty.
*
* @return A possibly-empty unmodifiable set of the fully qualified class
* names of the service types used
@@ -1234,7 +1381,8 @@ public class ModuleDescriptor
}
/**
- *
The services that this module provides.
+ *
Returns the set of {@code Provides} objects representing the
+ * services that the module provides.
*
* @return The possibly-empty unmodifiable set of the services that this
* module provides
@@ -1244,7 +1392,7 @@ public class ModuleDescriptor
}
/**
- * Returns this module's version.
+ *
Returns the module version.
*
* @return This module's version
*/
@@ -1253,10 +1401,10 @@ public class ModuleDescriptor
}
/**
- * Returns a string containing this module's name and, if present, its
- * version.
+ *
Returns a string containing the module name and, if present, its
+ * version.
*
- * @return A string containing this module's name and, if present, its
+ * @return A string containing the module name and, if present, its
* version.
*/
public String toNameAndVersion() {
@@ -1268,51 +1416,51 @@ public class ModuleDescriptor
}
/**
- * Returns the module's main class.
+ *
Returns the module main class.
*
- * @return The fully qualified class name of this module's main class
+ * @return The fully qualified class name of the module's main class
*/
public Optional mainClass() {
return Optional.ofNullable(mainClass);
}
/**
- * Returns the operating system name if this module is operating system
+ * Returns the operating system name if the module is operating system
* specific.
*
* @return The operating system name or an empty {@code Optional}
- * if this module is not operating system specific
+ * if the module is not operating system specific
*/
public Optional osName() {
return Optional.ofNullable(osName);
}
/**
- * Returns the operating system architecture if this module is operating
+ * Returns the operating system architecture if the module is operating
* system architecture specific.
*
* @return The operating system architecture or an empty {@code Optional}
- * if this module is not operating system architecture specific
+ * if the module is not operating system architecture specific
*/
public Optional osArch() {
return Optional.ofNullable(osArch);
}
/**
- * Returns the operating system version if this module is operating
+ * Returns the operating system version if the module is operating
* system version specific.
*
* @return The operating system version or an empty {@code Optional}
- * if this module is not operating system version specific
+ * if the module is not operating system version specific
*/
public Optional osVersion() {
return Optional.ofNullable(osVersion);
}
/**
- * Returns the names of all packages in this module.
+ * Returns the set of packages in the module.
*
- * @return A possibly-empty unmodifiable set of all packages in the module
+ * @return A possibly-empty unmodifiable set of the packages in the module
*/
public Set packages() {
return packages;
@@ -1320,37 +1468,53 @@ public class ModuleDescriptor
/**
- * A builder used for building {@link ModuleDescriptor} objects.
+ * A builder for building {@link ModuleDescriptor} objects.
*
- *
{@code ModuleDescriptor} defines the {@link #module module}, {@link
- * #openModule openModule}, and {@link #automaticModule automaticModule}
- * methods to create builders for building different kinds of modules.
+ *
{@code ModuleDescriptor} defines the {@link #newModule newModule},
+ * {@link #newOpenModule newOpenModule}, and {@link #newAutomaticModule
+ * newAutomaticModule} methods to create builders for building
+ * normal, open, and automatic modules.
+ *
+ *
The set of packages in the module are accumulated by the {@code
+ * Builder} as the {@link ModuleDescriptor.Builder#exports(String) exports},
+ * {@link ModuleDescriptor.Builder#opens(String) opens},
+ * {@link ModuleDescriptor.Builder#packages(Set) packages},
+ * {@link ModuleDescriptor.Builder#provides(String,List) provides}, and
+ * {@link ModuleDescriptor.Builder#mainClass(String) mainClass} methods are
+ * invoked.
+ *
+ *
The module names, package names, and class names that are parameters
+ * specified to the builder methods are the module names, package names,
+ * and qualified names of classes (in named packages) as defined in the
+ * The Java™ Language Specification.
*
* @apiNote A {@code Builder} checks the components and invariants as
- * components are added to the builder. The rational for this is to detect
+ * components are added to the builder. The rationale for this is to detect
* errors as early as possible and not defer all validation to the
- * {@link #build build} method. A {@code Builder} cannot be used to create
- * a {@link ModuleDescriptor#isSynthetic() synthetic} module.
+ * {@link #build build} method.
*
* @since 9
+ * @spec JPMS
*/
public static final class Builder {
final String name;
- final boolean strict; // true if module names are checked
+ final boolean strict;
+ final Set modifiers;
final boolean open;
- final boolean synthetic;
- boolean automatic;
+ final boolean automatic;
+ final Set packages = new HashSet<>();
final Map requires = new HashMap<>();
final Map exports = new HashMap<>();
final Map opens = new HashMap<>();
- final Set concealedPackages = new HashSet<>();
final Set uses = new HashSet<>();
final Map provides = new HashMap<>();
Version version;
@@ -1362,35 +1526,25 @@ public class ModuleDescriptor
/**
* Initializes a new builder with the given module name.
*
- * @param strict
- * Indicates whether module names are checked or not
+ * If {@code strict} is {@code true} then module, package, and class
+ * names are checked to ensure they are legal names. In addition, the
+ * {@link #build buid} method will add "{@code requires java.base}" if
+ * the dependency is not declared.
*/
- Builder(String name, boolean strict, boolean open, boolean synthetic) {
+ Builder(String name, boolean strict, Set modifiers) {
this.name = (strict) ? requireModuleName(name) : name;
this.strict = strict;
- this.open = open;
- this.synthetic = synthetic;
- }
-
- /* package */ Builder automatic(boolean automatic) {
- this.automatic = automatic;
- return this;
+ this.modifiers = modifiers;
+ this.open = modifiers.contains(Modifier.OPEN);
+ this.automatic = modifiers.contains(Modifier.AUTOMATIC);
+ assert !open || !automatic;
}
/**
- * Returns the set of packages that are exported (unconditionally or
- * unconditionally).
+ * Returns a snapshot of the packages in the module.
*/
- /* package */ Set exportedPackages() {
- return exports.keySet();
- }
-
- /**
- * Returns the set of packages that are opened (unconditionally or
- * unconditionally).
- */
- /* package */Set openPackages() {
- return opens.keySet();
+ /* package */ Set packages() {
+ return Collections.unmodifiableSet(packages);
}
/**
@@ -1406,8 +1560,12 @@ public class ModuleDescriptor
* initialized to build
* @throws IllegalStateException
* If the dependence on the module has already been declared
+ * or this builder is for an automatic module
*/
public Builder requires(Requires req) {
+ if (automatic)
+ throw new IllegalStateException("Automatic modules cannot declare"
+ + " dependences");
String mn = req.name();
if (name.equals(mn))
throw new IllegalArgumentException("Dependence on self");
@@ -1433,11 +1591,12 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If the module name is {@code null}, is not a legal Java
- * identifier, or is equal to the module name that this builder
+ * If the module name is {@code null}, is not a legal module
+ * name, or is equal to the module name that this builder
* was initialized to build
* @throws IllegalStateException
* If the dependence on the module has already been declared
+ * or this builder is for an automatic module
*/
public Builder requires(Set ms,
String mn,
@@ -1448,6 +1607,23 @@ public class ModuleDescriptor
return requires(new Requires(ms, mn, compiledVersion));
}
+ /* package */Builder requires(Set ms,
+ String mn,
+ String compiledVersion) {
+ Version v = null;
+ try {
+ v = Version.parse(compiledVersion);
+ } catch (IllegalArgumentException e) {
+ // for now, drop un-parsable version when non-strict
+ if (strict) throw e;
+ }
+ if (v == null) {
+ return requires(ms, mn);
+ } else {
+ return requires(ms, mn, v);
+ }
+ }
+
/**
* Adds a dependence on a module with the given (and possibly empty)
* set of modifiers.
@@ -1460,11 +1636,12 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If the module name is {@code null}, is not a legal Java
- * identifier, or is equal to the module name that this builder
+ * If the module name is {@code null}, is not a legal module
+ * name, or is equal to the module name that this builder
* was initialized to build
* @throws IllegalStateException
* If the dependence on the module has already been declared
+ * or this builder is for an automatic module
*/
public Builder requires(Set ms, String mn) {
if (strict)
@@ -1481,18 +1658,19 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If the module name is {@code null}, is not a legal Java
- * identifier, or is equal to the module name that this builder
+ * If the module name is {@code null}, is not a legal module
+ * name, or is equal to the module name that this builder
* was initialized to build
* @throws IllegalStateException
* If the dependence on the module has already been declared
+ * or this builder is for an automatic module
*/
public Builder requires(String mn) {
return requires(EnumSet.noneOf(Requires.Modifier.class), mn);
}
/**
- * Adds an export.
+ * Adds an exported package.
*
* @param e
* The export
@@ -1500,29 +1678,27 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method or the package is already
- * declared as exported
+ * If the {@link Exports#source package} is already declared as
+ * exported or this builder is for an automatic module
*/
public Builder exports(Exports e) {
- // can't be exported and concealed
- String source = e.source();
- if (concealedPackages.contains(source)) {
- throw new IllegalStateException("Package " + source
- + " already declared");
+ if (automatic) {
+ throw new IllegalStateException("Automatic modules cannot declare"
+ + " exported packages");
}
+ String source = e.source();
if (exports.containsKey(source)) {
throw new IllegalStateException("Exported package " + source
+ " already declared");
}
-
exports.put(source, e);
+ packages.add(source);
return this;
}
/**
- * Adds an export, with the given (and possibly empty) set of modifiers,
- * to export a package to a set of target modules.
+ * Adds an exported package with the given (and possibly empty) set of
+ * modifiers. The package is exported to a set of target modules.
*
* @param ms
* The set of modifiers
@@ -1534,33 +1710,34 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If the package name or any of the target modules is {@code
- * null} or is not a legal Java identifier, or the set of
- * targets is empty
+ * If the package name is {@code null} or is not a legal
+ * package name, the set of target modules is empty, or the set
+ * of target modules contains a name that is not a legal module
+ * name
* @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method or the package is already
- * declared as exported
+ * If the package is already declared as exported
+ * or this builder is for an automatic module
*/
public Builder exports(Set ms,
String pn,
Set targets)
{
- Exports e = new Exports(ms, requirePackageName(pn), targets);
+ Exports e = new Exports(ms, pn, targets);
// check targets
targets = e.targets();
if (targets.isEmpty())
throw new IllegalArgumentException("Empty target set");
- if (strict)
+ if (strict) {
+ requirePackageName(e.source());
targets.stream().forEach(Checks::requireModuleName);
-
+ }
return exports(e);
}
/**
- * Adds an unqualified export with the given (and possibly empty) set
- * of modifiers.
+ * Adds an exported package with the given (and possibly empty) set of
+ * modifiers. The package is exported to all modules.
*
* @param ms
* The set of modifiers
@@ -1570,160 +1747,22 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If the package name is {@code null} or is not a legal Java
- * identifier
+ * If the package name is {@code null} or is not a legal
+ * package name
* @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method or the package is already
- * declared as exported
+ * If the package is already declared as exported
+ * or this builder is for an automatic module
*/
public Builder exports(Set ms, String pn) {
- Exports e = new Exports(ms, requirePackageName(pn), Collections.emptySet());
+ if (strict) {
+ requirePackageName(pn);
+ }
+ Exports e = new Exports(ms, pn, Collections.emptySet());
return exports(e);
}
/**
- * Adds an export to export a package to a set of target modules.
- *
- * @param pn
- * The package name
- * @param targets
- * The set of target modules names
- *
- * @return This builder
- *
- * @throws IllegalArgumentException
- * If the package name or any of the target modules is {@code
- * null} or is not a legal Java identifier, or the set of
- * targets is empty
- * @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method or the package is already
- * declared as exported
- */
- public Builder exports(String pn, Set targets) {
- return exports(Collections.emptySet(), pn, targets);
- }
-
- /**
- * Adds an unqualified export.
- *
- * @param pn
- * The package name
- *
- * @return This builder
- *
- * @throws IllegalArgumentException
- * If the package name is {@code null} or is not a legal Java
- * identifier
- * @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method or the package is already
- * declared as exported
- */
- public Builder exports(String pn) {
- return exports(Collections.emptySet(), pn);
- }
-
- /**
- * Adds an opens directive.
- *
- * @param obj
- * The {@code Opens} object
- *
- * @return This builder
- *
- * @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method, the package is already
- * declared as open, or this is a builder for an open module
- */
- public Builder opens(Opens obj) {
- if (open) {
- throw new IllegalStateException("open modules cannot declare"
- + " open packages");
- }
-
- // can't be open and concealed
- String source = obj.source();
- if (concealedPackages.contains(source)) {
- throw new IllegalStateException("Package " + source
- + " already declared");
- }
- if (opens.containsKey(source)) {
- throw new IllegalStateException("Open package " + source
- + " already declared");
- }
-
- opens.put(source, obj);
- return this;
- }
-
-
- /**
- * Adds an opens directive, with the given (and possibly empty)
- * set of modifiers, to open a package to a set of target modules.
- *
- * @param ms
- * The set of modifiers
- * @param pn
- * The package name
- * @param targets
- * The set of target modules names
- *
- * @return This builder
- *
- * @throws IllegalArgumentException
- * If the package name or any of the target modules is {@code
- * null} or is not a legal Java identifier, or the set of
- * targets is empty
- * @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method, the package is already
- * declared as open, or this is a builder for an open module
- */
- public Builder opens(Set ms,
- String pn,
- Set targets)
- {
- Opens e = new Opens(ms, requirePackageName(pn), targets);
-
- // check targets
- targets = e.targets();
- if (targets.isEmpty())
- throw new IllegalArgumentException("Empty target set");
- if (strict)
- targets.stream().forEach(Checks::requireModuleName);
-
- return opens(e);
- }
-
- /**
- * Adds an opens directive to open a package with the given (and
- * possibly empty) set of modifiers.
- *
- * @param ms
- * The set of modifiers
- * @param pn
- * The package name
- *
- * @return This builder
- *
- * @throws IllegalArgumentException
- * If the package name is {@code null} or is not a legal Java
- * identifier
- * @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method, the package is already
- * declared as open, or this is a builder for an open module
- */
- public Builder opens(Set ms, String pn) {
- Opens e = new Opens(ms, requirePackageName(pn), Collections.emptySet());
- return opens(e);
- }
-
- /**
- * Adds an opens directive to open a package to a set of target
+ * Adds an exported package. The package is exported to a set of target
* modules.
*
* @param pn
@@ -1734,20 +1773,20 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If the package name or any of the target modules is {@code
- * null} or is not a legal Java identifier, or the set of
- * targets is empty
+ * If the package name is {@code null} or is not a legal
+ * package name, the set of target modules is empty, or the set
+ * of target modules contains a name that is not a legal module
+ * name
* @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method, the package is already
- * declared as open, or this is a builder for an open module
+ * If the package is already declared as exported
+ * or this builder is for an automatic module
*/
- public Builder opens(String pn, Set targets) {
- return opens(Collections.emptySet(), pn, targets);
+ public Builder exports(String pn, Set targets) {
+ return exports(Collections.emptySet(), pn, targets);
}
/**
- * Adds an opens directive to open a package.
+ * Adds an exported package. The package is exported to all modules.
*
* @param pn
* The package name
@@ -1755,12 +1794,146 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If the package name is {@code null} or is not a legal Java
- * identifier
+ * If the package name is {@code null} or is not a legal
+ * package name
* @throws IllegalStateException
- * If the package is already declared as a package with the
- * {@link #contains contains} method, the package is already
- * declared as open, or this is a builder for an open module
+ * If the package is already declared as exported
+ * or this builder is for an automatic module
+ */
+ public Builder exports(String pn) {
+ return exports(Collections.emptySet(), pn);
+ }
+
+ /**
+ * Adds an open package.
+ *
+ * @param obj
+ * The {@code Opens} object
+ *
+ * @return This builder
+ *
+ * @throws IllegalStateException
+ * If the package is already declared as open, or this is a
+ * builder for an open module or automatic module
+ */
+ public Builder opens(Opens obj) {
+ if (open || automatic) {
+ throw new IllegalStateException("Open or automatic modules cannot"
+ + " declare open packages");
+ }
+ String source = obj.source();
+ if (opens.containsKey(source)) {
+ throw new IllegalStateException("Open package " + source
+ + " already declared");
+ }
+ opens.put(source, obj);
+ packages.add(source);
+ return this;
+ }
+
+
+ /**
+ * Adds an open package with the given (and possibly empty) set of
+ * modifiers. The package is open to a set of target modules.
+ *
+ * @param ms
+ * The set of modifiers
+ * @param pn
+ * The package name
+ * @param targets
+ * The set of target modules names
+ *
+ * @return This builder
+ *
+ * @throws IllegalArgumentException
+ * If the package name is {@code null} or is not a legal
+ * package name, the set of target modules is empty, or the set
+ * of target modules contains a name that is not a legal module
+ * name
+ * @throws IllegalStateException
+ * If the package is already declared as open, or this is a
+ * builder for an open module or automatic module
+ */
+ public Builder opens(Set ms,
+ String pn,
+ Set targets)
+ {
+ Opens opens = new Opens(ms, pn, targets);
+
+ // check targets
+ targets = opens.targets();
+ if (targets.isEmpty())
+ throw new IllegalArgumentException("Empty target set");
+ if (strict) {
+ requirePackageName(opens.source());
+ targets.stream().forEach(Checks::requireModuleName);
+ }
+ return opens(opens);
+ }
+
+ /**
+ * Adds an open package with the given (and possibly empty) set of
+ * modifiers. The package is open to all modules.
+ *
+ * @param ms
+ * The set of modifiers
+ * @param pn
+ * The package name
+ *
+ * @return This builder
+ *
+ * @throws IllegalArgumentException
+ * If the package name is {@code null} or is not a legal
+ * package name
+ * @throws IllegalStateException
+ * If the package is already declared as open, or this is a
+ * builder for an open module or automatic module
+ */
+ public Builder opens(Set ms, String pn) {
+ if (strict) {
+ requirePackageName(pn);
+ }
+ Opens e = new Opens(ms, pn, Collections.emptySet());
+ return opens(e);
+ }
+
+ /**
+ * Adds an open package. The package is open to a set of target modules.
+ *
+ * @param pn
+ * The package name
+ * @param targets
+ * The set of target modules names
+ *
+ * @return This builder
+ *
+ * @throws IllegalArgumentException
+ * If the package name is {@code null} or is not a legal
+ * package name, the set of target modules is empty, or the set
+ * of target modules contains a name that is not a legal module
+ * name
+ * @throws IllegalStateException
+ * If the package is already declared as open, or this is a
+ * builder for an open module or automatic module
+ */
+ public Builder opens(String pn, Set targets) {
+ return opens(Collections.emptySet(), pn, targets);
+ }
+
+ /**
+ * Adds an open package. The package is open to all modules.
+ *
+ * @param pn
+ * The package name
+ *
+ * @return This builder
+ *
+ * @throws IllegalArgumentException
+ * If the package name is {@code null} or is not a legal
+ * package name
+ * @throws IllegalStateException
+ * If the package is already declared as open, or this is a
+ * builder for an open module or automatic module
*/
public Builder opens(String pn) {
return opens(Collections.emptySet(), pn);
@@ -1775,12 +1948,16 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If the service type is {@code null} or is not a legal Java
- * identifier
+ * If the service type is {@code null} or not a qualified name of
+ * a class in a named package
* @throws IllegalStateException
* If a dependency on the service type has already been declared
+ * or this is a builder for an an automatic module
*/
public Builder uses(String service) {
+ if (automatic)
+ throw new IllegalStateException("Automatic modules can not declare"
+ + " service dependences");
if (uses.contains(requireServiceTypeName(service)))
throw new IllegalStateException("Dependence upon service "
+ service + " already declared");
@@ -1789,7 +1966,9 @@ public class ModuleDescriptor
}
/**
- * Provides a service with one or more implementations.
+ * Provides a service with one or more implementations. The package for
+ * each {@link Provides#providers provider} (or provider factory) is
+ * added to the module if not already added.
*
* @param p
* The provides
@@ -1801,16 +1980,18 @@ public class ModuleDescriptor
* declared
*/
public Builder provides(Provides p) {
- String st = p.service();
- if (provides.containsKey(st))
+ String service = p.service();
+ if (provides.containsKey(service))
throw new IllegalStateException("Providers of service "
- + st + " already declared");
- provides.put(st, p);
+ + service + " already declared");
+ provides.put(service, p);
+ p.providers().forEach(name -> packages.add(packageName(name)));
return this;
}
/**
- * Provides implementations of a service.
+ * Provides implementations of a service. The package for each provider
+ * (or provider factory) is added to the module if not already added.
*
* @param service
* The service type
@@ -1821,103 +2002,59 @@ public class ModuleDescriptor
*
* @throws IllegalArgumentException
* If the service type or any of the provider class names is
- * {@code null} or is not a legal Java identifier, or the list
- * of provider class names is empty
+ * {@code null} or not a qualified name of a class in a named
+ * package, or the list of provider class names is empty
* @throws IllegalStateException
* If the providers for the service type have already been
* declared
*/
public Builder provides(String service, List providers) {
- if (provides.containsKey(service))
- throw new IllegalStateException("Providers of service "
- + service + " already declared by " + name);
-
- Provides p = new Provides(requireServiceTypeName(service), providers);
+ Provides p = new Provides(service, providers);
// check providers after the set has been copied.
List providerNames = p.providers();
if (providerNames.isEmpty())
throw new IllegalArgumentException("Empty providers set");
- providerNames.forEach(Checks::requireServiceProviderName);
- provides.put(service, p);
- return this;
+ if (strict) {
+ requireServiceTypeName(p.service());
+ providerNames.forEach(Checks::requireServiceProviderName);
+ } else {
+ // Disallow service/providers in unnamed package
+ String pn = packageName(service);
+ if (pn.isEmpty()) {
+ throw new IllegalArgumentException(service
+ + ": unnamed package");
+ }
+ for (String name : providerNames) {
+ pn = packageName(name);
+ if (pn.isEmpty()) {
+ throw new IllegalArgumentException(name
+ + ": unnamed package");
+ }
+ }
+ }
+ return provides(p);
}
/**
- * Provides an implementation of a service.
- *
- * @param service
- * The service type
- * @param provider
- * The provider or provider factory class name
- *
- * @return This builder
- *
- * @throws IllegalArgumentException
- * If the service type or the provider class name is {@code
- * null} or is not a legal Java identifier
- * @throws IllegalStateException
- * If the providers for the service type have already been
- * declared
- */
- public Builder provides(String service, String provider) {
- if (provider == null)
- throw new IllegalArgumentException("'provider' is null");
- return provides(service, List.of(provider));
- }
-
- /**
- * Adds a (possible empty) set of packages to the module
+ * Adds packages to the module. All packages in the set of package names
+ * that are not in the module are added to module.
*
* @param pns
- * The set of package names
+ * The (possibly empty) set of package names
*
* @return This builder
*
* @throws IllegalArgumentException
* If any of the package names is {@code null} or is not a
- * legal Java identifier
- * @throws IllegalStateException
- * If any of packages are already declared as packages in
- * the module. This includes packages that are already
- * declared as exported or open packages.
+ * legal package name
*/
- public Builder contains(Set pns) {
- pns.forEach(this::contains);
- return this;
- }
-
- /**
- * Adds a package to the module.
- *
- * @param pn
- * The package name
- *
- * @return This builder
- *
- * @throws IllegalArgumentException
- * If the package name is {@code null}, or is not a legal Java
- * identifier
- * @throws IllegalStateException
- * If the package is already declared as a package in the
- * module. This includes the package already declared as an
- * exported or open package.
- */
- public Builder contains(String pn) {
- Checks.requirePackageName(pn);
- if (concealedPackages.contains(pn)) {
- throw new IllegalStateException("Package " + pn
- + " already declared");
+ public Builder packages(Set pns) {
+ if (strict) {
+ pns = new HashSet<>(pns);
+ pns.forEach(Checks::requirePackageName);
}
- if (exports.containsKey(pn)) {
- throw new IllegalStateException("Exported package "
- + pn + " already declared");
- }
- if (opens.containsKey(pn)) {
- throw new IllegalStateException("Open package "
- + pn + " already declared");
- }
- concealedPackages.add(pn);
+ this.packages.addAll(pns);
return this;
}
@@ -1937,22 +2074,35 @@ public class ModuleDescriptor
/**
* Sets the module version.
*
- * @param v
+ * @param vs
* The version string to parse
*
* @return This builder
*
* @throws IllegalArgumentException
- * If {@code v} is null or cannot be parsed as a version string
+ * If {@code vs} is {@code null} or cannot be parsed as a
+ * version string
*
* @see Version#parse(String)
*/
- public Builder version(String v) {
- return version(Version.parse(v));
+ public Builder version(String vs) {
+ Version v;
+ if (strict) {
+ v = Version.parse(vs);
+ } else {
+ try {
+ v = Version.parse(vs);
+ } catch (IllegalArgumentException ignore) {
+ // for now, ignore when non-strict
+ return this;
+ }
+ }
+ return version(v);
}
/**
- * Sets the module main class.
+ * Sets the module main class. The package for the main class is added
+ * to the module if not already added.
*
* @param mc
* The module main class
@@ -1960,10 +2110,24 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If {@code mainClass} is null or is not a legal Java identifier
+ * If {@code mainClass} is {@code null} or not a qualified
+ * name of a class in a named package
*/
public Builder mainClass(String mc) {
- mainClass = requireBinaryName("main class name", mc);
+ String pn;
+ if (strict) {
+ mc = requireQualifiedClassName("main class name", mc);
+ pn = packageName(mc);
+ assert !pn.isEmpty();
+ } else {
+ // Disallow main class in unnamed package
+ pn = packageName(mc);
+ if (pn.isEmpty()) {
+ throw new IllegalArgumentException(mc + ": unnamed package");
+ }
+ }
+ mainClass = mc;
+ packages.add(pn);
return this;
}
@@ -1976,7 +2140,7 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If {@code name} is null or the empty String
+ * If {@code name} is {@code null} or the empty String
*/
public Builder osName(String name) {
if (name == null || name.isEmpty())
@@ -1994,7 +2158,7 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If {@code name} is null or the empty String
+ * If {@code name} is {@code null} or the empty String
*/
public Builder osArch(String arch) {
if (arch == null || arch.isEmpty())
@@ -2012,7 +2176,7 @@ public class ModuleDescriptor
* @return This builder
*
* @throws IllegalArgumentException
- * If {@code name} is null or the empty String
+ * If {@code name} is {@code null} or the empty String
*/
public Builder osVersion(String version) {
if (version == null || version.isEmpty())
@@ -2024,26 +2188,34 @@ public class ModuleDescriptor
/**
* Builds and returns a {@code ModuleDescriptor} from its components.
*
+ *
The module will require "{@code java.base}" even if the dependence
+ * has not been declared (the exception is when building a module named
+ * "{@code java.base}" as it cannot require itself). The dependence on
+ * "{@code java.base}" will have the {@link
+ * java.lang.module.ModuleDescriptor.Requires.Modifier#MANDATED MANDATED}
+ * modifier if the dependence was not declared.
+ *
* @return The module descriptor
*/
public ModuleDescriptor build() {
Set requires = new HashSet<>(this.requires.values());
-
- Set packages = new HashSet<>();
- packages.addAll(exports.keySet());
- packages.addAll(opens.keySet());
- packages.addAll(concealedPackages);
-
Set exports = new HashSet<>(this.exports.values());
Set opens = new HashSet<>(this.opens.values());
+ // add dependency on java.base
+ if (strict
+ && !name.equals("java.base")
+ && !this.requires.containsKey("java.base")) {
+ requires.add(new Requires(Set.of(Requires.Modifier.MANDATED),
+ "java.base",
+ null));
+ }
+
Set provides = new HashSet<>(this.provides.values());
return new ModuleDescriptor(name,
version,
- open,
- automatic,
- synthetic,
+ modifiers,
requires,
exports,
opens,
@@ -2062,16 +2234,20 @@ public class ModuleDescriptor
* Compares this module descriptor to another.
*
*
Two {@code ModuleDescriptor} objects are compared by comparing their
- * module name lexicographically. Where the module names are equal then
- * the versions, if present, are compared.
- *
- * @apiNote For now, the natural ordering is not consistent with equals.
- * If two module descriptors have equal module names, equal versions if
- * present, but their corresponding components are not equal, then they
- * will be considered equal by this method.
+ * module names lexicographically. Where the module names are equal then the
+ * module versions are compared. When comparing the module versions then a
+ * module descriptor with a version is considered to succeed a module
+ * descriptor that does not have a version. Where the module names are equal
+ * and the versions are equal (or not present in both), then the set of
+ * modifiers are compared. Sets of modifiers are compared by comparing
+ * a binary value computed for each set. If a modifier is present
+ * in the set then the bit at the position of its ordinal is {@code 1}
+ * in the binary value, otherwise {@code 0}. If the two set of modifiers
+ * are also equal then the other components of the module descriptors are
+ * compared in a manner that is consistent with {@code equals}.
*
* @param that
- * The object to which this module descriptor is to be compared
+ * The module descriptor to compare
*
* @return A negative integer, zero, or a positive integer if this module
* descriptor is less than, equal to, or greater than the given
@@ -2079,16 +2255,50 @@ public class ModuleDescriptor
*/
@Override
public int compareTo(ModuleDescriptor that) {
+ if (this == that) return 0;
+
int c = this.name().compareTo(that.name());
if (c != 0) return c;
- if (version == null) {
- if (that.version == null)
- return 0;
- return -1;
- }
- if (that.version == null)
- return +1;
- return version.compareTo(that.version);
+
+ c = compare(this.version, that.version);
+ if (c != 0) return c;
+
+ long v1 = modsValue(this.modifiers());
+ long v2 = modsValue(that.modifiers());
+ c = Long.compare(v1, v2);
+ if (c != 0) return c;
+
+ c = compare(this.requires, that.requires);
+ if (c != 0) return c;
+
+ c = compare(this.packages, that.packages);
+ if (c != 0) return c;
+
+ c = compare(this.exports, that.exports);
+ if (c != 0) return c;
+
+ c = compare(this.opens, that.opens);
+ if (c != 0) return c;
+
+ c = compare(this.uses, that.uses);
+ if (c != 0) return c;
+
+ c = compare(this.provides, that.provides);
+ if (c != 0) return c;
+
+ c = compare(this.mainClass, that.mainClass);
+ if (c != 0) return c;
+
+ c = compare(this.osName, that.osName);
+ if (c != 0) return c;
+
+ c = compare(this.osArch, that.osArch);
+ if (c != 0) return c;
+
+ c = compare(this.osVersion, that.osVersion);
+ if (c != 0) return c;
+
+ return 0;
}
/**
@@ -2115,10 +2325,9 @@ public class ModuleDescriptor
return false;
ModuleDescriptor that = (ModuleDescriptor)ob;
return (name.equals(that.name)
- && open == that.open
- && automatic == that.automatic
- && synthetic == that.synthetic
+ && modifiers.equals(that.modifiers)
&& requires.equals(that.requires)
+ && Objects.equals(packages, that.packages)
&& exports.equals(that.exports)
&& opens.equals(that.opens)
&& uses.equals(that.uses)
@@ -2127,12 +2336,9 @@ public class ModuleDescriptor
&& Objects.equals(mainClass, that.mainClass)
&& Objects.equals(osName, that.osName)
&& Objects.equals(osArch, that.osArch)
- && Objects.equals(osVersion, that.osVersion)
- && Objects.equals(packages, that.packages));
+ && Objects.equals(osVersion, that.osVersion));
}
- private transient int hash; // cached hash code
-
/**
* Computes a hash code for this module descriptor.
*
@@ -2147,10 +2353,9 @@ public class ModuleDescriptor
int hc = hash;
if (hc == 0) {
hc = name.hashCode();
- hc = hc * 43 + Boolean.hashCode(open);
- hc = hc * 43 + Boolean.hashCode(automatic);
- hc = hc * 43 + Boolean.hashCode(synthetic);
+ hc = hc * 43 + Objects.hashCode(modifiers);
hc = hc * 43 + requires.hashCode();
+ hc = hc * 43 + Objects.hashCode(packages);
hc = hc * 43 + exports.hashCode();
hc = hc * 43 + opens.hashCode();
hc = hc * 43 + uses.hashCode();
@@ -2160,18 +2365,18 @@ public class ModuleDescriptor
hc = hc * 43 + Objects.hashCode(osName);
hc = hc * 43 + Objects.hashCode(osArch);
hc = hc * 43 + Objects.hashCode(osVersion);
- hc = hc * 43 + Objects.hashCode(packages);
if (hc == 0)
hc = -1;
hash = hc;
}
return hc;
}
+ private transient int hash; // cached hash code
/**
- * Returns a string describing this descriptor.
+ *
Returns a string describing the module.
*
- * @return A string describing this descriptor
+ * @return A string describing the module
*/
@Override
public String toString() {
@@ -2201,31 +2406,50 @@ public class ModuleDescriptor
*
* @param name
* The module name
+ * @param ms
+ * The set of module modifiers
*
* @return A new builder
*
* @throws IllegalArgumentException
- * If the module name is {@code null} or is not a legal Java
- * identifier
+ * If the module name is {@code null} or is not a legal module
+ * name, or the set of modifiers contains {@link
+ * Modifier#AUTOMATIC AUTOMATIC} with other modifiers
*/
- public static Builder module(String name) {
- return new Builder(name, true, false, false);
+ public static Builder newModule(String name, Set ms) {
+ Set mods = new HashSet<>(ms);
+ if (mods.contains(Modifier.AUTOMATIC) && mods.size() > 1)
+ throw new IllegalArgumentException("AUTOMATIC cannot be used with"
+ + " other modifiers");
+
+ return new Builder(name, true, mods);
+ }
+
+ /**
+ * Instantiates a builder to build a module descriptor for a normal
+ * module. This method is equivalent to invoking {@link #newModule(String,Set)
+ * newModule} with an empty set of {@link ModuleDescriptor.Modifier modifiers}.
+ *
+ * @param name
+ * The module name
+ *
+ * @return A new builder
+ *
+ * @throws IllegalArgumentException
+ * If the module name is {@code null} or is not a legal module
+ * name
+ */
+ public static Builder newModule(String name) {
+ return new Builder(name, true, Set.of());
}
/**
* Instantiates a builder to build a module descriptor for an open module.
- * An open module does not declare any open packages but the resulting
- * module is treated as if all packages are open.
+ * This method is equivalent to invoking {@link #newModule(String,Set)
+ * newModule} with the {@link ModuleDescriptor.Modifier#OPEN OPEN} modifier.
*
- *
As an example, the following creates a module descriptor for an open
- * name "{@code m}" containing two packages, one of which is exported.
The builder for an open module cannot be used to declare any open
+ * packages.
*
* @param name
* The module name
@@ -2233,19 +2457,22 @@ public class ModuleDescriptor
* @return A new builder that builds an open module
*
* @throws IllegalArgumentException
- * If the module name is {@code null} or is not a legal Java
- * identifier
+ * If the module name is {@code null} or is not a legal module
+ * name
*/
- public static Builder openModule(String name) {
- return new Builder(name, true, true, false);
+ public static Builder newOpenModule(String name) {
+ return new Builder(name, true, Set.of(Modifier.OPEN));
}
/**
* Instantiates a builder to build a module descriptor for an automatic
- * module. Automatic modules receive special treatment during resolution
- * (see {@link Configuration}) so that they read all other modules. When
- * Instantiated in the Java virtual machine as a {@link java.lang.reflect.Module}
- * then the Module reads every unnamed module in the Java virtual machine.
+ * module. This method is equivalent to invoking {@link #newModule(String,Set)
+ * newModule} with the {@link ModuleDescriptor.Modifier#AUTOMATIC AUTOMATIC}
+ * modifier.
+ *
+ *
The builder for an automatic module cannot be used to declare module
+ * or service dependences. It also cannot be used to declare any exported
+ * or open packages.
*
* @param name
* The module name
@@ -2253,13 +2480,13 @@ public class ModuleDescriptor
* @return A new builder that builds an automatic module
*
* @throws IllegalArgumentException
- * If the module name is {@code null} or is not a legal Java
- * identifier
+ * If the module name is {@code null} or is not a legal module
+ * name
*
* @see ModuleFinder#of(Path[])
*/
- public static Builder automaticModule(String name) {
- return new Builder(name, true, false, false).automatic(true);
+ public static Builder newAutomaticModule(String name) {
+ return new Builder(name, true, Set.of(Modifier.AUTOMATIC));
}
@@ -2269,8 +2496,12 @@ public class ModuleDescriptor
*
*
If the descriptor encoded in the input stream does not indicate a
* set of packages in the module then the {@code packageFinder} will be
- * invoked. If the {@code packageFinder} throws an {@link UncheckedIOException}
- * then {@link IOException} cause will be re-thrown.
+ * invoked. The set of packages that the {@code packageFinder} returns
+ * must include all the packages that the module exports, opens, as well
+ * as the packages of the service implementations that the module provides,
+ * and the package of the main class (if the module has a main class). If
+ * the {@code packageFinder} throws an {@link UncheckedIOException} then
+ * {@link IOException} cause will be re-thrown.
*
*
If there are bytes following the module descriptor then it is
* implementation specific as to whether those bytes are read, ignored,
@@ -2292,7 +2523,9 @@ public class ModuleDescriptor
* @return The module descriptor
*
* @throws InvalidModuleDescriptorException
- * If an invalid module descriptor is detected
+ * If an invalid module descriptor is detected or the set of
+ * packages returned by the {@code packageFinder} does not include
+ * all of the packages obtained from the module descriptor
* @throws IOException
* If an I/O error occurs reading from the input stream or {@code
* UncheckedIOException} is thrown by the package finder
@@ -2305,8 +2538,12 @@ public class ModuleDescriptor
}
/**
- * Reads the binary form of a module declaration from an input stream
- * as a module descriptor.
+ * Reads the binary form of a module declaration from an input stream as a
+ * module descriptor. This method works exactly as specified by the 2-arg
+ * {@link #read(InputStream,Supplier) read} method with the exception that
+ * a packager finder is not used to find additional packages when the
+ * module descriptor read from the stream does not indicate the set of
+ * packages.
*
* @param in
* The input stream
@@ -2327,7 +2564,13 @@ public class ModuleDescriptor
* as a module descriptor.
*
*
If the descriptor encoded in the byte buffer does not indicate a
- * set of packages then the {@code packageFinder} will be invoked.
+ * set of packages in the module then the {@code packageFinder} will be
+ * invoked. The set of packages that the {@code packageFinder} returns
+ * must include all the packages that the module exports, opens, as well
+ * as the packages of the service implementations that the module provides,
+ * and the package of the main class (if the module has a main class). If
+ * the {@code packageFinder} throws an {@link UncheckedIOException} then
+ * {@link IOException} cause will be re-thrown.
*
*
The module descriptor is read from the buffer stating at index
* {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position()
@@ -2353,7 +2596,9 @@ public class ModuleDescriptor
* @return The module descriptor
*
* @throws InvalidModuleDescriptorException
- * If an invalid module descriptor is detected
+ * If an invalid module descriptor is detected or the set of
+ * packages returned by the {@code packageFinder} does not include
+ * all of the packages obtained from the module descriptor
*/
public static ModuleDescriptor read(ByteBuffer bb,
Supplier> packageFinder)
@@ -2362,8 +2607,11 @@ public class ModuleDescriptor
}
/**
- * Reads the binary form of a module declaration from a byte buffer
- * as a module descriptor.
+ * Reads the binary form of a module declaration from a byte buffer as a
+ * module descriptor. This method works exactly as specified by the 2-arg
+ * {@link #read(ByteBuffer,Supplier) read} method with the exception that a
+ * packager finder is not used to find additional packages when the module
+ * descriptor encoded in the buffer does not indicate the set of packages.
*
* @param bb
* The byte buffer
@@ -2398,6 +2646,11 @@ public class ModuleDescriptor
}
}
+ private static String packageName(String cn) {
+ int index = cn.lastIndexOf('.');
+ return (index == -1) ? "" : cn.substring(0, index);
+ }
+
/**
* Returns a string containing the given set of modifiers and label.
*/
@@ -2407,6 +2660,36 @@ public class ModuleDescriptor
.collect(Collectors.joining(" "));
}
+ private static >
+ int compare(T obj1, T obj2) {
+ if (obj1 != null) {
+ return (obj2 != null) ? obj1.compareTo(obj2) : 1;
+ } else {
+ return (obj2 == null) ? 0 : -1;
+ }
+ }
+
+ /**
+ * Compares two sets of {@code Comparable} objects.
+ */
+ @SuppressWarnings("unchecked")
+ private static >
+ int compare(Set s1, Set s2) {
+ T[] a1 = (T[]) s1.toArray();
+ T[] a2 = (T[]) s2.toArray();
+ Arrays.sort(a1);
+ Arrays.sort(a2);
+ return Arrays.compare(a1, a2);
+ }
+
+ private static > long modsValue(Set set) {
+ long value = 0;
+ for (Enum e : set) {
+ value += 1 << e.ordinal();
+ }
+ return value;
+ }
+
static {
/**
* Setup the shared secret to allow code in other packages access
@@ -2417,19 +2700,21 @@ public class ModuleDescriptor
@Override
public Builder newModuleBuilder(String mn,
boolean strict,
- boolean open,
- boolean synthetic) {
- return new Builder(mn, strict, open, synthetic);
+ Set modifiers) {
+ return new Builder(mn, strict, modifiers);
}
@Override
- public Set exportedPackages(ModuleDescriptor.Builder builder) {
- return builder.exportedPackages();
+ public Set packages(ModuleDescriptor.Builder builder) {
+ return builder.packages();
}
@Override
- public Set openPackages(ModuleDescriptor.Builder builder) {
- return builder.openPackages();
+ public void requires(ModuleDescriptor.Builder builder,
+ Set ms,
+ String mn,
+ String compiledVersion) {
+ builder.requires(ms, mn, compiledVersion);
}
@Override
@@ -2466,23 +2751,10 @@ public class ModuleDescriptor
return new Provides(service, providers, true);
}
- @Override
- public Version newVersion(String v) {
- return new Version(v);
- }
-
- @Override
- public ModuleDescriptor newModuleDescriptor(ModuleDescriptor md,
- Set pkgs) {
- return new ModuleDescriptor(md, pkgs);
- }
-
@Override
public ModuleDescriptor newModuleDescriptor(String name,
Version version,
- boolean open,
- boolean automatic,
- boolean synthetic,
+ Set modifiers,
Set requires,
Set exports,
Set opens,
@@ -2496,9 +2768,7 @@ public class ModuleDescriptor
int hashCode) {
return new ModuleDescriptor(name,
version,
- open,
- automatic,
- synthetic,
+ modifiers,
requires,
exports,
opens,
@@ -2514,12 +2784,12 @@ public class ModuleDescriptor
}
@Override
- public Configuration resolveRequiresAndUses(ModuleFinder finder,
- Collection roots,
- boolean check,
- PrintStream traceOutput)
+ public Configuration resolveAndBind(ModuleFinder finder,
+ Collection roots,
+ boolean check,
+ PrintStream traceOutput)
{
- return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
+ return Configuration.resolveAndBind(finder, roots, check, traceOutput);
}
});
}
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
index 5d01f698806..9fc03dc87b5 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,14 +42,15 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import jdk.internal.module.ModuleBootstrap;
import jdk.internal.module.ModulePath;
import jdk.internal.module.SystemModuleFinder;
import sun.security.action.GetPropertyAction;
/**
* A finder of modules. A {@code ModuleFinder} is used to find modules during
- * resolution or
- * service binding.
+ * resolution or
+ * service binding.
*
*
A {@code ModuleFinder} can only find one module with a given name. A
* {@code ModuleFinder} that finds modules in a sequence of directories, for
@@ -85,6 +86,7 @@ import sun.security.action.GetPropertyAction;
*
A {@code ModuleFinder} is not required to be thread safe.
*
* @since 9
+ * @spec JPMS
*/
public interface ModuleFinder {
@@ -124,8 +126,8 @@ public interface ModuleFinder {
* to find that module.
*
* @apiNote This is important to have for methods such as {@link
- * Configuration#resolveRequiresAndUses resolveRequiresAndUses} that need
- * to scan the module path to find modules that provide a specific service.
+ * Configuration#resolveAndBind resolveAndBind} that need to scan the
+ * module path to find modules that provide a specific service.
*
* @return The set of all module references that this finder locates
*
@@ -172,7 +174,8 @@ public interface ModuleFinder {
} else {
Path mlib = Paths.get(home, "modules");
if (Files.isDirectory(mlib)) {
- return of(mlib);
+ // exploded build may be patched
+ return ModulePath.of(ModuleBootstrap.patcher(), mlib);
} else {
throw new InternalError("Unable to detect the run-time image");
}
@@ -198,13 +201,9 @@ public interface ModuleFinder {
*
*
If an element is a path to a directory of modules then each entry in
* the directory is a packaged module or the top-level directory of an
- * exploded module. The module finder's {@link #find(String) find} or
- * {@link #findAll() findAll} methods throw {@link FindException} if a
- * directory containing more than one module with the same name is
- * encountered.
- *
- *
If an element in the array is a path to a directory, and that
- * directory contains a file named {@code module-info.class}, then the
+ * exploded module. It it an error if a directory contains more than one
+ * module with the same name. If an element is a path to a directory, and
+ * that directory contains a file named {@code module-info.class}, then the
* directory is treated as an exploded module rather than a directory of
* modules.
*
@@ -214,9 +213,8 @@ public interface ModuleFinder {
* entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release}
* JAR file) is a modular JAR and is an explicit module.
* A JAR file that does not have a {@code module-info.class} in the
- * top-level directory is an {@link ModuleDescriptor#isAutomatic automatic}
- * module. The {@link ModuleDescriptor} for an automatic module is created as
- * follows:
+ * top-level directory is created as an automatic module. The components
+ * for the automatic module are derived as follows:
*
*
It {@link ModuleDescriptor#requires() requires} {@code
- * java.base}.
- *
- *
The set of packages in the module is derived from the names
- * of non-directory entries in the JAR file. A candidate package name
- * is derived from an entry using the characters up to, but not
- * including, the last forward slash. All remaining forward slashes are
- * replaced with dot ({@code "."}). If the resulting string is a valid
- * Java identifier then it is assumed to be a package name. For example,
- * if the JAR file contains an entry "{@code p/q/Foo.class}" then the
- * package name derived is "{@code p.q}". All packages are {@link
- * ModuleDescriptor#exports() exported}.
+ *
The set of packages in the module is derived from the
+ * non-directory entries in the JAR file that have names ending in
+ * "{@code .class}". A candidate package name is derived from the name
+ * using the characters up to, but not including, the last forward slash.
+ * All remaining forward slashes are replaced with dot ({@code "."}). If
+ * the resulting string is a legal package name then it is assumed to be
+ * a package name. For example, if the JAR file contains the entry
+ * "{@code p/q/Foo.class}" then the package name derived is
+ * "{@code p.q}".
*
*
The contents of entries starting with {@code
* META-INF/services/} are assumed to be service configuration files
* (see {@link java.util.ServiceLoader}). If the name of a file
- * (that follows {@code META-INF/services/}) is a legal Java identifier
- * then it is assumed to be the fully-qualified binary name of a
- * service type. The entries in the file are assumed to be the
- * fully-qualified binary names of provider classes.
+ * (that follows {@code META-INF/services/}) is a legal class name
+ * then it is assumed to be the fully-qualified class name of a service
+ * type. The entries in the file are assumed to be the fully-qualified
+ * class names of provider classes.
*
*
If the JAR file has a {@code Main-Class} attribute in its
- * main manifest then its value is the {@link
+ * main manifest then its value is the module {@link
* ModuleDescriptor#mainClass() main class}.
*
*
*
*
If a {@code ModuleDescriptor} cannot be created (by means of the
* {@link ModuleDescriptor.Builder ModuleDescriptor.Builder} API) for an
- * automatic module then {@code FindException} is thrown. This can arise,
- * for example, when a legal Java identifier name cannot be derived from
- * the file name of the JAR file or where the JAR file contains a {@code
- * .class} in the top-level directory of the JAR file.
+ * automatic module then {@code FindException} is thrown. This can arise
+ * when a legal module name cannot be derived from the file name of the JAR
+ * file, where the JAR file contains a {@code .class} in the top-level
+ * directory of the JAR file, where an entry in a service configuration
+ * file is not a legal class name or its package name is not in the set of
+ * packages derived for the module, or where the module main class is not
+ * a legal class name or its package is not in the module.
*
*
In addition to JAR files, an implementation may also support modules
- * that are packaged in other implementation specific module formats. When
- * a file is encountered that is not recognized as a packaged module then
- * {@code FindException} is thrown. An implementation may choose to ignore
- * some files, {@link java.nio.file.Files#isHidden hidden} files for
- * example. Paths to files that do not exist are always ignored.
+ * that are packaged in other implementation specific module formats. If
+ * an element in the array specified to this method is a path to a directory
+ * of modules then entries in the directory that not recognized as modules
+ * are ignored. If an element in the array is a path to a packaged module
+ * that is not recognized then a {@code FindException} is thrown when the
+ * file is encountered. Paths to files that do not exist are always ignored.
+ *
*
*
As with automatic modules, the contents of a packaged or exploded
* module may need to be scanned in order to determine the packages
@@ -325,7 +325,7 @@ public interface ModuleFinder {
};
}
- return new ModulePath(entries);
+ return ModulePath.of(entries);
}
/**
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java
index d79d210edd0..c5a7b61c695 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java
@@ -45,7 +45,7 @@ import java.util.stream.Stream;
* module. A module reader is also intended to be used by {@code ClassLoader}
* implementations that load classes and resources from modules.
*
- *
A resource in a module is identified by a name that is a
+ *
A resource in a module is identified by an abstract name that is a
* '{@code /}'-separated path string. For example, module {@code java.base} may
* have a resource "{@code java/lang/Object.class}" that, by convention, is the
* class file for {@code java.lang.Object}.
@@ -61,8 +61,18 @@ import java.util.stream.Stream;
* open}, {@link #read read}, and {@link #list list} methods may throw {@code
* SecurityException} if access is denied by the security manager.
*
+ * @implSpec Implementations of {@code ModuleReader} should take great care
+ * when translating an abstract resource name to the location of a resource in
+ * a packaged module or on the file system. Implementations are advised to
+ * treat resource names with elements such as '{@code .}, '{@code ..}',
+ * elements containing file separators, or empty elements as "not found". More
+ * generally, if the resource name is not in the stream of elements that the
+ * {@code list} method returns then the resource should be treated as "not
+ * found" to avoid inconsistencies.
+ *
* @see ModuleReference
* @since 9
+ * @spec JPMS
*/
public interface ModuleReader extends Closeable {
@@ -148,6 +158,9 @@ public interface ModuleReader extends Closeable {
* If an I/O error occurs or the module reader is closed
* @throws SecurityException
* If denied by the security manager
+ * @throws OutOfMemoryError
+ * If the resource is larger than {@code Integer.MAX_VALUE},
+ * the maximum capacity of a byte buffer
*
* @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain)
*/
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java
index 09a5acec219..54291e78dcc 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java
@@ -44,6 +44,7 @@ import java.util.Optional;
* @see ModuleFinder
* @see ModuleReader
* @since 9
+ * @spec JPMS
*/
public abstract class ModuleReference {
@@ -76,7 +77,7 @@ public abstract class ModuleReference {
/**
* Returns the location of this module's content, if known.
*
- *
This URI, when present, is used as the {@linkplain
+ *
This URI, when present, can be used as the {@linkplain
* java.security.CodeSource#getLocation location} value of a {@link
* java.security.CodeSource CodeSource} so that a module's classes can be
* granted specific permissions when loaded by a {@link
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java b/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java
index fb14cfe8200..69cc71f3466 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,12 @@
package java.lang.module;
/**
- * Thrown when resolving a set of modules or binding fails.
+ * Thrown when resolving a set of modules, or resolving a set of modules with
+ * service binding, fails.
*
* @see Configuration
* @since 9
+ * @spec JPMS
*/
public class ResolutionException extends RuntimeException {
private static final long serialVersionUID = -1031186845316729450L;
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java b/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java
index 05ef3c4dc1c..a3858ef6c13 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java
@@ -37,6 +37,7 @@ import java.util.Set;
* module's content.
*
* @since 9
+ * @spec JPMS
* @see Configuration#modules()
*/
public final class ResolvedModule {
diff --git a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
index d2aafdc5d87..1a44475b442 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,8 +49,8 @@ import jdk.internal.module.ModuleHashes;
import jdk.internal.module.ModuleReferenceImpl;
/**
- * The resolver used by {@link Configuration#resolveRequires} and
- * {@link Configuration#resolveRequiresAndUses}.
+ * The resolver used by {@link Configuration#resolve} and {@link
+ * Configuration#resolveAndBind}.
*
* @implNote The resolver is used at VM startup and so deliberately avoids
* using lambda and stream usages in code paths used during startup.
@@ -66,7 +66,19 @@ final class Resolver {
// maps module name to module reference
private final Map nameToReference = new HashMap<>();
+ // module constraints on target platform
+ private String osName;
+ private String osArch;
+ private String osVersion;
+ String osName() { return osName; }
+ String osArch() { return osArch; }
+ String osVersion() { return osVersion; }
+
+ /**
+ * @throws IllegalArgumentException if there are more than one parent and
+ * the constraints on the target platform conflict
+ */
Resolver(ModuleFinder beforeFinder,
List parents,
ModuleFinder afterFinder,
@@ -75,15 +87,54 @@ final class Resolver {
this.parents = parents;
this.afterFinder = afterFinder;
this.traceOutput = traceOutput;
+
+ // record constraints on target platform, checking that they don't conflict
+ for (Configuration parent : parents) {
+ String value = parent.osName();
+ if (value != null) {
+ if (osName == null) {
+ osName = value;
+ } else {
+ if (!value.equals(osName)) {
+ failParentConflict("Operating System", osName, value);
+ }
+ }
+ }
+ value = parent.osArch();
+ if (value != null) {
+ if (osArch == null) {
+ osArch = value;
+ } else {
+ if (!value.equals(osArch)) {
+ failParentConflict("OS architecture", osArch, value);
+ }
+ }
+ }
+ value = parent.osVersion();
+ if (value != null) {
+ if (osVersion == null) {
+ osVersion = value;
+ } else {
+ if (!value.equals(osVersion)) {
+ failParentConflict("OS version", osVersion, value);
+ }
+ }
+ }
+ }
}
+ private void failParentConflict(String constraint, String s1, String s2) {
+ String msg = "Parents have conflicting constraints on target "
+ + constraint + ": " + s1 + ", " + s2;
+ throw new IllegalArgumentException(msg);
+ }
/**
* Resolves the given named modules.
*
* @throws ResolutionException
*/
- Resolver resolveRequires(Collection roots) {
+ Resolver resolve(Collection roots) {
// create the visit stack to get us started
Deque q = new ArrayDeque<>();
@@ -100,7 +151,7 @@ final class Resolver {
mref = findWithAfterFinder(root);
if (mref == null) {
- fail("Module %s not found", root);
+ findFail("Module %s not found", root);
}
}
@@ -109,8 +160,7 @@ final class Resolver {
mref.location().ifPresent(uri -> trace(" (%s)", uri));
}
- assert mref.descriptor().name().equals(root);
- nameToReference.put(root, mref);
+ addFoundModule(mref);
q.push(mref.descriptor());
}
@@ -152,19 +202,19 @@ final class Resolver {
mref = findWithAfterFinder(dn);
if (mref == null) {
- fail("Module %s not found, required by %s",
- dn, descriptor.name());
+ findFail("Module %s not found, required by %s",
+ dn, descriptor.name());
}
}
if (!nameToReference.containsKey(dn)) {
- nameToReference.put(dn, mref);
+ addFoundModule(mref);
q.offer(mref.descriptor());
resolved.add(mref.descriptor());
if (isTracing()) {
trace("Module %s located, required by %s",
- dn, descriptor.name());
+ dn, descriptor.name());
mref.location().ifPresent(uri -> trace(" (%s)", uri));
}
}
@@ -181,7 +231,7 @@ final class Resolver {
* Augments the set of resolved modules with modules induced by the
* service-use relation.
*/
- Resolver resolveUses() {
+ Resolver bind() {
// Scan the finders for all available service provider modules. As
// java.base uses services then then module finders will be scanned
@@ -246,7 +296,7 @@ final class Resolver {
mref.location()
.ifPresent(uri -> trace(" (%s)", uri));
}
- nameToReference.put(pn, mref);
+ addFoundModule(mref);
q.push(provider);
}
}
@@ -263,6 +313,81 @@ final class Resolver {
}
+ /**
+ * Add the module to the nameToReference map. Also check any constraints on
+ * the target platform with the constraints of other modules.
+ */
+ private void addFoundModule(ModuleReference mref) {
+ ModuleDescriptor descriptor = mref.descriptor();
+ nameToReference.put(descriptor.name(), mref);
+
+ if (descriptor.osName().isPresent()
+ || descriptor.osArch().isPresent()
+ || descriptor.osVersion().isPresent())
+ checkTargetConstraints(descriptor);
+ }
+
+ /**
+ * Check that the module's constraints on the target platform do not
+ * conflict with the constraints of other modules resolved so far or
+ * modules in parent configurations.
+ */
+ private void checkTargetConstraints(ModuleDescriptor descriptor) {
+ String value = descriptor.osName().orElse(null);
+ if (value != null) {
+ if (osName == null) {
+ osName = value;
+ } else {
+ if (!value.equals(osName)) {
+ failTargetConstraint(descriptor);
+ }
+ }
+ }
+ value = descriptor.osArch().orElse(null);
+ if (value != null) {
+ if (osArch == null) {
+ osArch = value;
+ } else {
+ if (!value.equals(osArch)) {
+ failTargetConstraint(descriptor);
+ }
+ }
+ }
+ value = descriptor.osVersion().orElse(null);
+ if (value != null) {
+ if (osVersion == null) {
+ osVersion = value;
+ } else {
+ if (!value.equals(osVersion)) {
+ failTargetConstraint(descriptor);
+ }
+ }
+ }
+ }
+
+ private void failTargetConstraint(ModuleDescriptor md) {
+ String s1 = targetAsString(osName, osArch, osVersion);
+ String s2 = targetAsString(md);
+ findFail("Module %s has constraints on target platform that conflict" +
+ " with other modules: %s, %s", md.name(), s1, s2);
+ }
+
+ private String targetAsString(ModuleDescriptor descriptor) {
+ String osName = descriptor.osName().orElse(null);
+ String osArch = descriptor.osArch().orElse(null);
+ String osVersion = descriptor.osVersion().orElse(null);
+ return targetAsString(osName, osArch, osVersion);
+ }
+
+ private String targetAsString(String osName, String osArch, String osVersion) {
+ return new StringJoiner("-")
+ .add(Objects.toString(osName, "*"))
+ .add(Objects.toString(osArch, "*"))
+ .add(Objects.toString(osVersion, "*"))
+ .toString();
+ }
+
+
/**
* Execute post-resolution checks and returns the module graph of resolved
* modules as {@code Map}. The resolved modules will be in the given
@@ -281,7 +406,6 @@ final class Resolver {
if (check) {
detectCycles();
- checkPlatformConstraints();
checkHashes();
}
@@ -319,8 +443,7 @@ final class Resolver {
if (!visited.contains(descriptor)) {
boolean added = visitPath.add(descriptor);
if (!added) {
- throw new ResolutionException("Cycle detected: " +
- cycleAsString(descriptor));
+ resolveFail("Cycle detected: %s", cycleAsString(descriptor));
}
for (ModuleDescriptor.Requires requires : descriptor.requires()) {
String dn = requires.name();
@@ -353,86 +476,6 @@ final class Resolver {
}
- /**
- * If there are platform specific modules then check that the OS name,
- * architecture and version match.
- *
- * @apiNote This method does not currently check if the OS matches
- * platform specific modules in parent configurations.
- */
- private void checkPlatformConstraints() {
-
- // first module encountered that is platform specific
- String savedModuleName = null;
- String savedOsName = null;
- String savedOsArch = null;
- String savedOsVersion = null;
-
- for (ModuleReference mref : nameToReference.values()) {
- ModuleDescriptor descriptor = mref.descriptor();
-
- String osName = descriptor.osName().orElse(null);
- String osArch = descriptor.osArch().orElse(null);
- String osVersion = descriptor.osVersion().orElse(null);
-
- if (osName != null || osArch != null || osVersion != null) {
-
- if (savedModuleName == null) {
-
- savedModuleName = descriptor.name();
- savedOsName = osName;
- savedOsArch = osArch;
- savedOsVersion = osVersion;
-
- } else {
-
- boolean matches = platformMatches(osName, savedOsName)
- && platformMatches(osArch, savedOsArch)
- && platformMatches(osVersion, savedOsVersion);
-
- if (!matches) {
- String s1 = platformAsString(savedOsName,
- savedOsArch,
- savedOsVersion);
-
- String s2 = platformAsString(osName, osArch, osVersion);
- fail("Mismatching constraints on target platform: "
- + savedModuleName + ": " + s1
- + ", " + descriptor.name() + ": " + s2);
- }
-
- }
-
- }
- }
-
- }
-
- /**
- * Returns true if the s1 and s2 are equal or one of them is null.
- */
- private boolean platformMatches(String s1, String s2) {
- if (s1 == null || s2 == null)
- return true;
- else
- return Objects.equals(s1, s2);
- }
-
- /**
- * Return a string that encodes the OS name/arch/version.
- */
- private String platformAsString(String osName,
- String osArch,
- String osVersion) {
-
- return new StringJoiner("-")
- .add(Objects.toString(osName, "*"))
- .add(Objects.toString(osArch, "*"))
- .add(Objects.toString(osVersion, "*"))
- .toString();
-
- }
-
/**
* Checks the hashes in the module descriptor to ensure that they match
* any recorded hashes.
@@ -460,7 +503,7 @@ final class Resolver {
continue;
if (!(mref2 instanceof ModuleReferenceImpl)) {
- fail("Unable to compute the hash of module %s", dn);
+ findFail("Unable to compute the hash of module %s", dn);
}
// skip checking the hash if the module has been patched
@@ -469,11 +512,11 @@ final class Resolver {
byte[] recordedHash = hashes.hashFor(dn);
byte[] actualHash = other.computeHash(algorithm);
if (actualHash == null)
- fail("Unable to compute the hash of module %s", dn);
+ findFail("Unable to compute the hash of module %s", dn);
if (!Arrays.equals(recordedHash, actualHash)) {
- fail("Hash of %s (%s) differs to expected hash (%s)" +
- " recorded in %s", dn, toHexString(actualHash),
- toHexString(recordedHash), descriptor.name());
+ findFail("Hash of %s (%s) differs to expected hash (%s)" +
+ " recorded in %s", dn, toHexString(actualHash),
+ toHexString(recordedHash), descriptor.name());
}
}
}
@@ -694,37 +737,38 @@ final class Resolver {
for (ResolvedModule endpoint : reads) {
ModuleDescriptor descriptor2 = endpoint.descriptor();
- for (ModuleDescriptor.Exports export : descriptor2.exports()) {
+ if (descriptor2.isAutomatic()) {
+ // automatic modules read self and export all packages
+ if (descriptor2 != descriptor1){
+ for (String source : descriptor2.packages()) {
+ ModuleDescriptor supplier
+ = packageToExporter.putIfAbsent(source, descriptor2);
- if (export.isQualified()) {
- if (!export.targets().contains(descriptor1.name()))
- continue;
- }
-
- // source is exported to descriptor2
- String source = export.source();
- ModuleDescriptor other
- = packageToExporter.putIfAbsent(source, descriptor2);
-
- if (other != null && other != descriptor2) {
- // package might be local to descriptor1
- if (other == descriptor1) {
- fail("Module %s contains package %s"
- + ", module %s exports package %s to %s",
- descriptor1.name(),
- source,
- descriptor2.name(),
- source,
- descriptor1.name());
- } else {
- fail("Modules %s and %s export package %s to module %s",
- descriptor2.name(),
- other.name(),
- source,
- descriptor1.name());
+ // descriptor2 and 'supplier' export source to descriptor1
+ if (supplier != null) {
+ failTwoSuppliers(descriptor1, source, descriptor2, supplier);
+ }
}
}
+ } else {
+ for (ModuleDescriptor.Exports export : descriptor2.exports()) {
+ if (export.isQualified()) {
+ if (!export.targets().contains(descriptor1.name()))
+ continue;
+ }
+
+ // source is exported by descriptor2
+ String source = export.source();
+ ModuleDescriptor supplier
+ = packageToExporter.putIfAbsent(source, descriptor2);
+
+ // descriptor2 and 'supplier' export source to descriptor1
+ if (supplier != null) {
+ failTwoSuppliers(descriptor1, source, descriptor2, supplier);
+ }
+ }
+
}
}
@@ -735,8 +779,8 @@ final class Resolver {
for (String service : descriptor1.uses()) {
String pn = packageName(service);
if (!packageToExporter.containsKey(pn)) {
- fail("Module %s does not read a module that exports %s",
- descriptor1.name(), pn);
+ resolveFail("Module %s does not read a module that exports %s",
+ descriptor1.name(), pn);
}
}
@@ -744,15 +788,8 @@ final class Resolver {
for (ModuleDescriptor.Provides provides : descriptor1.provides()) {
String pn = packageName(provides.service());
if (!packageToExporter.containsKey(pn)) {
- fail("Module %s does not read a module that exports %s",
- descriptor1.name(), pn);
- }
-
- for (String provider : provides.providers()) {
- if (!packages.contains(packageName(provider))) {
- fail("Provider %s not in module %s",
- provider, descriptor1.name());
- }
+ resolveFail("Module %s does not read a module that exports %s",
+ descriptor1.name(), pn);
}
}
@@ -762,6 +799,42 @@ final class Resolver {
}
+ /**
+ * Fail because a module in the configuration exports the same package to
+ * a module that reads both. This includes the case where a module M
+ * containing a package p reads another module that exports p to at least
+ * module M.
+ */
+ private void failTwoSuppliers(ModuleDescriptor descriptor,
+ String source,
+ ModuleDescriptor supplier1,
+ ModuleDescriptor supplier2) {
+
+ if (supplier2 == descriptor) {
+ ModuleDescriptor tmp = supplier1;
+ supplier1 = supplier2;
+ supplier2 = tmp;
+ }
+
+ if (supplier1 == descriptor) {
+ resolveFail("Module %s contains package %s"
+ + ", module %s exports package %s to %s",
+ descriptor.name(),
+ source,
+ supplier2.name(),
+ source,
+ descriptor.name());
+ } else {
+ resolveFail("Modules %s and %s export package %s to module %s",
+ supplier1.name(),
+ supplier2.name(),
+ source,
+ descriptor.name());
+ }
+
+ }
+
+
/**
* Find a module of the given name in the parent configurations
*/
@@ -779,24 +852,16 @@ final class Resolver {
* Invokes the beforeFinder to find method to find the given module.
*/
private ModuleReference findWithBeforeFinder(String mn) {
- try {
- return beforeFinder.find(mn).orElse(null);
- } catch (FindException e) {
- // unwrap
- throw new ResolutionException(e.getMessage(), e.getCause());
- }
+
+ return beforeFinder.find(mn).orElse(null);
+
}
/**
* Invokes the afterFinder to find method to find the given module.
*/
private ModuleReference findWithAfterFinder(String mn) {
- try {
- return afterFinder.find(mn).orElse(null);
- } catch (FindException e) {
- // unwrap
- throw new ResolutionException(e.getMessage(), e.getCause());
- }
+ return afterFinder.find(mn).orElse(null);
}
/**
@@ -804,34 +869,27 @@ final class Resolver {
* and after ModuleFinders.
*/
private Set findAll() {
- try {
+ Set beforeModules = beforeFinder.findAll();
+ Set afterModules = afterFinder.findAll();
- Set beforeModules = beforeFinder.findAll();
- Set afterModules = afterFinder.findAll();
+ if (afterModules.isEmpty())
+ return beforeModules;
- if (afterModules.isEmpty())
- return beforeModules;
+ if (beforeModules.isEmpty()
+ && parents.size() == 1
+ && parents.get(0) == Configuration.empty())
+ return afterModules;
- if (beforeModules.isEmpty()
- && parents.size() == 1
- && parents.get(0) == Configuration.empty())
- return afterModules;
-
- Set result = new HashSet<>(beforeModules);
- for (ModuleReference mref : afterModules) {
- String name = mref.descriptor().name();
- if (!beforeFinder.find(name).isPresent()
- && findInParent(name) == null) {
- result.add(mref);
- }
+ Set result = new HashSet<>(beforeModules);
+ for (ModuleReference mref : afterModules) {
+ String name = mref.descriptor().name();
+ if (!beforeFinder.find(name).isPresent()
+ && findInParent(name) == null) {
+ result.add(mref);
}
-
- return result;
-
- } catch (FindException e) {
- // unwrap
- throw new ResolutionException(e.getMessage(), e.getCause());
}
+
+ return result;
}
/**
@@ -842,10 +900,18 @@ final class Resolver {
return (index == -1) ? "" : cn.substring(0, index);
}
+ /**
+ * Throw FindException with the given format string and arguments
+ */
+ private static void findFail(String fmt, Object ... args) {
+ String msg = String.format(fmt, args);
+ throw new FindException(msg);
+ }
+
/**
* Throw ResolutionException with the given format string and arguments
*/
- private static void fail(String fmt, Object ... args) {
+ private static void resolveFail(String fmt, Object ... args) {
String msg = String.format(fmt, args);
throw new ResolutionException(msg);
}
diff --git a/jdk/src/java.base/share/classes/java/lang/module/package-info.java b/jdk/src/java.base/share/classes/java/lang/module/package-info.java
index f641638cb2c..1d830079cab 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/package-info.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,112 @@
* Classes to support module descriptors and creating configurations of modules
* by means of resolution and service binding.
*
+ *
Resolution is the process of computing the transitive closure of a set
+ * of root modules over a set of observable modules by resolving the
+ * dependences expressed by {@link
+ * java.lang.module.ModuleDescriptor.Requires requires} clauses.
+ * The dependence graph is augmented with edges that take account of
+ * implicitly declared dependences ({@code requires transitive}) to create a
+ * readability graph. The result of resolution is a {@link
+ * java.lang.module.Configuration Configuration} that encapsulates the
+ * readability graph.
+ *
+ *
As an example, suppose we have the following observable modules:
If the module {@code m1} is resolved then the resulting configuration
+ * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in
+ * its readability graph are:
Resolution is an additive process. When computing the transitive closure
+ * then the dependence relation may include dependences on modules in {@link
+ * java.lang.module.Configuration#parents() parent} configurations. The result
+ * is a relative configuration that is relative to one or more parent
+ * configurations and where the readability graph may have edges from modules
+ * in the configuration to modules in parent configurations.
+ *
+ *
As an example, suppose we have the following observable modules:
If module {@code m1} is resolved with the configuration for the {@link
+ * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting
+ * configuration contains two modules ({@code m1}, {@code m2}). The edges in
+ * its readability graph are:
+ *
{@code
+ * m1 --> m2
+ * m1 --> java.xml
+ * }
+ * where module {@code java.xml} is in the parent configuration. For
+ * simplicity, this example omits the implicitly declared dependence on the
+ * {@code java.base} module.
+ *
+ *
Requires clauses that are "{@code requires static}" express an optional
+ * dependence (except at compile-time). If a module declares that it
+ * "{@code requires static M}" then resolution does not search the observable
+ * modules for "{@code M}". However, if "{@code M}" is resolved (because resolution
+ * resolves a module that requires "{@code M}" without the {@link
+ * java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC static} modifier)
+ * then the readability graph will contain read edges for each module that
+ * "{@code requires static M}".
+ *
+ *
{@link java.lang.module.ModuleDescriptor#isAutomatic() Automatic} modules
+ * receive special treatment during resolution. Each automatic module is resolved
+ * so that it reads all other modules in the configuration and all parent
+ * configurations. Each automatic module is also resolved as if it
+ * "{@code requires transitive}" all other automatic modules in the configuration
+ * (and all automatic modules in parent configurations).
Service binding is the process of augmenting a graph of resolved modules
+ * from the set of observable modules induced by the service-use dependence
+ * ({@code uses} and {@code provides} clauses). Any module that was not
+ * previously in the graph requires resolution to compute its transitive
+ * closure. Service binding is an iterative process in that adding a module
+ * that satisfies some service-use dependence may introduce new service-use
+ * dependences.
If the module {@code m1} is resolved then the resulting graph of modules
+ * has one module ({@code m1}). If the graph is augmented with modules induced
+ * by the service-use dependence relation then the configuration will contain
+ * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in
+ * its readability graph are:
The edges in the conceptual service-use graph are:
+ *
{@code
+ * m1 --> m2 (meaning m1 uses a service that is provided by m2)
+ * m1 --> m3
+ * }
+ *
+ *
General Exceptions
+ *
*
Unless otherwise noted, passing a {@code null} argument to a constructor
* or method of any class or interface in this package will cause a {@link
* java.lang.NullPointerException NullPointerException} to be thrown. Additionally,
@@ -34,6 +140,7 @@
* will cause a {@code NullPointerException}, unless otherwise specified.
*
* @since 9
+ * @spec JPMS
*/
package java.lang.module;
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
index f585b476504..503ce8dfb1e 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,38 +28,44 @@ package java.lang.reflect;
import java.lang.annotation.Annotation;
import java.security.AccessController;
-import jdk.internal.misc.VM;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.ReflectionFactory;
-import sun.security.action.GetPropertyAction;
/**
- * The AccessibleObject class is the base class for Field, Method and
- * Constructor objects. It provides the ability to flag a reflected
- * object as suppressing default Java language access control checks
- * when it is used. The access checks -- module boundaries,
- * public, default (package) access, protected, and private members --
- * are performed when Fields, Methods or Constructors are used to set
- * or get fields, to invoke methods or to create and initialize new
- * instances of classes, respectively. Unlike access control specified
- * in the The Java™ Language Specification and
- * The Java Virtual Machine Specification, access checks
- * with reflected objects assume {@link Module#canRead readability}.
+ * The {@code AccessibleObject} class is the base class for {@code Field},
+ * {@code Method}, and {@code Constructor} objects (known as reflected
+ * objects). It provides the ability to flag a reflected object as
+ * suppressing checks for Java language access control when it is used. This
+ * permits sophisticated applications with sufficient privilege, such as Java
+ * Object Serialization or other persistence mechanisms, to manipulate objects
+ * in a manner that would normally be prohibited.
*
- *
Setting the {@code accessible} flag in a reflected object
- * permits sophisticated applications with sufficient privilege, such
- * as Java Object Serialization or other persistence mechanisms, to
- * manipulate objects in a manner that would normally be prohibited.
+ *
Java language access control prevents use of private members outside
+ * their class; package access members outside their package; protected members
+ * outside their package or subclasses; and public members outside their
+ * module unless they are declared in an {@link Module#isExported(String,Module)
+ * exported} package and the user {@link Module#canRead reads} their module. By
+ * default, Java language access control is enforced (with one variation) when
+ * {@code Field}s, {@code Method}s, or {@code Constructor}s are used to get or
+ * set fields, to invoke methods, or to create and initialize new instances of
+ * classes, respectively. Every reflected object checks that the code using it
+ * is in an appropriate class, package, or module.
*
- *
By default, a reflected object is not accessible.
+ *
The one variation from Java language access control is that the checks
+ * by reflected objects assume readability. That is, the module containing
+ * the use of a reflected object is assumed to read the module in which
+ * the underlying field, method, or constructor is declared.
Whether the checks for Java language access control can be suppressed
+ * (and thus, whether access can be enabled) depends on whether the reflected
+ * object corresponds to a member in an exported or open package
+ * (see {@link #setAccessible(boolean)}).
*
+ * @jls 6.6 Access Control
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
public class AccessibleObject implements AnnotatedElement {
@@ -78,15 +84,11 @@ public class AccessibleObject implements AnnotatedElement {
/**
* Convenience method to set the {@code accessible} flag for an
- * array of objects with a single security check (for efficiency).
+ * array of reflected objects with a single security check (for efficiency).
*
- *
This method cannot be used to enable access to an object that is a
- * {@link Member member} of a class in a different module to the caller and
- * where the class is in a package that is not exported to the caller's
- * module. Additionally, if the member is non-public or its declaring
- * class is non-public, then this method can only be used to enable access
- * if the package is {@link Module#isOpen(String,Module) open} to at least
- * the caller's module.
+ *
This method may be used to enable access to all reflected objects in
+ * the array when access to each reflected object can be enabled as
+ * specified by {@link #setAccessible(boolean) setAccessible(boolean)}.
*
*
If there is a security manager, its
* {@code checkPermission} method is first called with a
@@ -99,10 +101,15 @@ public class AccessibleObject implements AnnotatedElement {
* @param array the array of AccessibleObjects
* @param flag the new value for the {@code accessible} flag
* in each object
- * @throws InaccessibleObjectException if access cannot be enabled
- * @throws SecurityException if the request is denied.
+ * @throws InaccessibleObjectException if access cannot be enabled for all
+ * objects in the array
+ * @throws SecurityException if the request is denied by the security manager
+ * or an element in the array is a constructor for {@code
+ * java.lang.Class}
* @see SecurityManager#checkPermission
* @see ReflectPermission
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static void setAccessible(AccessibleObject[] array, boolean flag) {
@@ -120,41 +127,143 @@ public class AccessibleObject implements AnnotatedElement {
}
/**
- * Set the {@code accessible} flag for this object to
+ * Set the {@code accessible} flag for this reflected object to
* the indicated boolean value. A value of {@code true} indicates that
- * the reflected object should suppress Java language access
- * checking when it is used. A value of {@code false} indicates
- * that the reflected object should enforce Java language access checks
- * while assuming readability (as noted in the class description).
+ * the reflected object should suppress checks for Java language access
+ * control when it is used. A value of {@code false} indicates that
+ * the reflected object should enforce checks for Java language access
+ * control when it is used, with the variation noted in the class description.
*
- *
This method cannot be used to enable access to an object that is a
- * {@link Member member} of a class in a different module to the caller and
- * where the class is in a package that is not exported to the caller's
- * module. Additionally, if the member is non-public or its declaring
- * class is non-public, then this method can only be used to enable access
- * if the package is {@link Module#isOpen(String,Module) open} to at least
- * the caller's module.
+ *
This method may be used by a caller in class {@code C} to enable
+ * access to a {@link Member member} of {@link Member#getDeclaringClass()
+ * declaring class} {@code D} if any of the following hold:
*
- *
If there is a security manager, its
+ *
+ *
{@code C} and {@code D} are in the same module.
+ *
+ *
The member is {@code public} and {@code D} is {@code public} in
+ * a package that the module containing {@code D} {@link
+ * Module#isExported(String,Module) exports} to at least the module
+ * containing {@code C}.
+ *
+ *
The member is {@code protected} {@code static}, {@code D} is
+ * {@code public} in a package that the module containing {@code D}
+ * exports to at least the module containing {@code C}, and {@code C}
+ * is a subclass of {@code D}.
+ *
+ *
{@code D} is in a package that the module containing {@code D}
+ * {@link Module#isOpen(String,Module) opens} to at least the module
+ * containing {@code C}.
+ * All packages in unnamed and open modules are open to all modules and
+ * so this method always succeeds when {@code D} is in an unnamed or
+ * open module.
+ *
+ *
+ *
This method cannot be used to enable access to private members,
+ * members with default (package) access, protected instance members, or
+ * protected constructors when the declaring class is in a different module
+ * to the caller and the package containing the declaring class is not open
+ * to the caller's module.
+ *
+ *
If there is a security manager, its
* {@code checkPermission} method is first called with a
* {@code ReflectPermission("suppressAccessChecks")} permission.
*
* @param flag the new value for the {@code accessible} flag
* @throws InaccessibleObjectException if access cannot be enabled
- * @throws SecurityException if the request is denied
- * @see SecurityManager#checkPermission
- * @see ReflectPermission
+ * @throws SecurityException if the request is denied by the security manager
+ * @see #trySetAccessible
* @see java.lang.invoke.MethodHandles#privateLookupIn
+ * @revised 9
+ * @spec JPMS
*/
public void setAccessible(boolean flag) {
AccessibleObject.checkPermission();
setAccessible0(flag);
}
- void setAccessible0(boolean flag) {
+ /**
+ * Sets the accessible flag and returns the new value
+ */
+ boolean setAccessible0(boolean flag) {
this.override = flag;
+ return flag;
}
+ /**
+ * Set the {@code accessible} flag for this reflected object to {@code true}
+ * if possible. This method sets the {@code accessible} flag, as if by
+ * invoking {@link #setAccessible(boolean) setAccessible(true)}, and returns
+ * the possibly-updated value for the {@code accessible} flag. If access
+ * cannot be enabled, i.e. the checks or Java language access control cannot
+ * be suppressed, this method returns {@code false} (as opposed to {@code
+ * setAccessible(true)} throwing {@code InaccessibleObjectException} when
+ * it fails).
+ *
+ *
This method is a no-op if the {@code accessible} flag for
+ * this reflected object is {@code true}.
+ *
+ *
For example, a caller can invoke {@code trySetAccessible}
+ * on a {@code Method} object for a private instance method
+ * {@code p.T::privateMethod} to suppress the checks for Java language access
+ * control when the {@code Method} is invoked.
+ * If {@code p.T} class is in a different module to the caller and
+ * package {@code p} is open to at least the caller's module,
+ * the code below successfully sets the {@code accessible} flag
+ * to {@code true}.
+ *
+ *
+ * {@code
+ * p.T obj = ....; // instance of p.T
+ * :
+ * Method m = p.T.class.getDeclaredMethod("privateMethod");
+ * if (m.trySetAccessible()) {
+ * m.invoke(obj);
+ * } else {
+ * // package p is not opened to the caller to access private member of T
+ * ...
+ * }
+ * }
+ *
+ *
If there is a security manager, its {@code checkPermission} method
+ * is first called with a {@code ReflectPermission("suppressAccessChecks")}
+ * permission.
+ *
+ * @return {@code true} if the {@code accessible} flag is set to {@code true};
+ * {@code false} if access cannot be enabled.
+ * @throws SecurityException if the request is denied by the security manager
+ *
+ * @since 9
+ * @spec JPMS
+ * @see java.lang.invoke.MethodHandles#privateLookupIn
+ */
+ @CallerSensitive
+ public final boolean trySetAccessible() {
+ AccessibleObject.checkPermission();
+
+ if (override == true) return true;
+
+ // if it's not a Constructor, Method, Field then no access check
+ if (!Member.class.isInstance(this)) {
+ return setAccessible0(true);
+ }
+
+ // does not allow to suppress access check for Class's constructor
+ Class> declaringClass = ((Member) this).getDeclaringClass();
+ if (declaringClass == Class.class && this instanceof Constructor) {
+ return false;
+ }
+
+ if (checkCanSetAccessible(Reflection.getCallerClass(),
+ declaringClass,
+ false)) {
+ return setAccessible0(true);
+ } else {
+ return false;
+ }
+ }
+
+
/**
* If the given AccessibleObject is a {@code Constructor}, {@code Method}
* or {@code Field} then checks that its declaring class is in a package
@@ -164,22 +273,29 @@ public class AccessibleObject implements AnnotatedElement {
// do nothing, needs to be overridden by Constructor, Method, Field
}
+
void checkCanSetAccessible(Class> caller, Class> declaringClass) {
+ checkCanSetAccessible(caller, declaringClass, true);
+ }
+
+ private boolean checkCanSetAccessible(Class> caller,
+ Class> declaringClass,
+ boolean throwExceptionIfDenied) {
Module callerModule = caller.getModule();
Module declaringModule = declaringClass.getModule();
- if (callerModule == declaringModule) return;
- if (callerModule == Object.class.getModule()) return;
- if (!declaringModule.isNamed()) return;
+ if (callerModule == declaringModule) return true;
+ if (callerModule == Object.class.getModule()) return true;
+ if (!declaringModule.isNamed()) return true;
// package is open to caller
String pn = packageName(declaringClass);
if (declaringModule.isOpen(pn, callerModule)) {
- printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule);
- return;
+ dumpStackIfOpenedReflectively(declaringModule, pn, callerModule);
+ return true;
}
- // package is exported to caller and class/member is public
+ // package is exported to caller
boolean isExported = declaringModule.isExported(pn, callerModule);
boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
int modifiers;
@@ -188,48 +304,72 @@ public class AccessibleObject implements AnnotatedElement {
} else {
modifiers = ((Field) this).getModifiers();
}
- boolean isMemberPublic = Modifier.isPublic(modifiers);
- if (isExported && isClassPublic && isMemberPublic) {
- printStackTraceIfExportedReflectively(declaringModule, pn, callerModule);
- return;
+ if (isExported && isClassPublic) {
+
+ // member is public
+ if (Modifier.isPublic(modifiers)) {
+ dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
+ return true;
+ }
+
+ // member is protected-static
+ if (Modifier.isProtected(modifiers)
+ && Modifier.isStatic(modifiers)
+ && isSubclassOf(caller, declaringClass)) {
+ dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
+ return true;
+ }
}
- // not accessible
- String msg = "Unable to make ";
- if (this instanceof Field)
- msg += "field ";
- msg += this + " accessible: " + declaringModule + " does not \"";
- if (isClassPublic && isMemberPublic)
- msg += "exports";
- else
- msg += "opens";
- msg += " " + pn + "\" to " + callerModule;
- InaccessibleObjectException e = new InaccessibleObjectException(msg);
- if (Reflection.printStackTraceWhenAccessFails()) {
- e.printStackTrace(System.err);
+ if (throwExceptionIfDenied) {
+ // not accessible
+ String msg = "Unable to make ";
+ if (this instanceof Field)
+ msg += "field ";
+ msg += this + " accessible: " + declaringModule + " does not \"";
+ if (isClassPublic && Modifier.isPublic(modifiers))
+ msg += "exports";
+ else
+ msg += "opens";
+ msg += " " + pn + "\" to " + callerModule;
+ InaccessibleObjectException e = new InaccessibleObjectException(msg);
+ if (Reflection.printStackTraceWhenAccessFails()) {
+ e.printStackTrace(System.err);
+ }
+ throw e;
}
- throw e;
+ return false;
}
- private void printStackTraceIfOpenedReflectively(Module module,
- String pn,
- Module other) {
- printStackTraceIfExposedReflectively(module, pn, other, true);
+ private boolean isSubclassOf(Class> queryClass, Class> ofClass) {
+ while (queryClass != null) {
+ if (queryClass == ofClass) {
+ return true;
+ }
+ queryClass = queryClass.getSuperclass();
+ }
+ return false;
}
- private void printStackTraceIfExportedReflectively(Module module,
- String pn,
- Module other) {
- printStackTraceIfExposedReflectively(module, pn, other, false);
+ private void dumpStackIfOpenedReflectively(Module module,
+ String pn,
+ Module other) {
+ dumpStackIfExposedReflectively(module, pn, other, true);
}
- private void printStackTraceIfExposedReflectively(Module module,
- String pn,
- Module other,
- boolean open)
+ private void dumpStackIfExportedReflectively(Module module,
+ String pn,
+ Module other) {
+ dumpStackIfExposedReflectively(module, pn, other, false);
+ }
+
+ private void dumpStackIfExposedReflectively(Module module,
+ String pn,
+ Module other,
+ boolean open)
{
if (Reflection.printStackTraceWhenAccessSucceeds()
- && !module.isStaticallyExportedOrOpen(pn, other, open))
+ && !module.isStaticallyExportedOrOpen(pn, other, open))
{
String msg = other + " allowed to invoke setAccessible on ";
if (this instanceof Field)
@@ -256,14 +396,99 @@ public class AccessibleObject implements AnnotatedElement {
}
/**
- * Get the value of the {@code accessible} flag for this object.
+ * Get the value of the {@code accessible} flag for this reflected object.
*
* @return the value of the object's {@code accessible} flag
+ *
+ * @deprecated
+ * This method is deprecated because its name hints that it checks
+ * if the reflected object is accessible when it actually indicates
+ * if the checks for Java language access control are suppressed.
+ * This method may return {@code false} on a reflected object that is
+ * accessible to the caller. To test if this reflected object is accessible,
+ * it should use {@link #canAccess(Object)}.
+ *
+ * @revised 9
*/
+ @Deprecated(since="9")
public boolean isAccessible() {
return override;
}
+ /**
+ * Test if the caller can access this reflected object. If this reflected
+ * object corresponds to an instance method or field then this method tests
+ * if the caller can access the given {@code obj} with the reflected object.
+ * For instance methods or fields then the {@code obj} argument must be an
+ * instance of the {@link Member#getDeclaringClass() declaring class}. For
+ * static members and constructors then {@code obj} must be {@code null}.
+ *
+ *
This method returns {@code true} if the {@code accessible} flag
+ * is set to {@code true}, i.e. the checks for Java language access control
+ * are suppressed, or if the caller can access the member as
+ * specified in The Java™ Language Specification,
+ * with the variation noted in the class description.
+ *
+ * @param obj an instance object of the declaring class of this reflected
+ * object if it is an instance method or field
+ *
+ * @return {@code true} if the caller can access this reflected object.
+ *
+ * @throws IllegalArgumentException
+ *
+ *
if this reflected object is a static member or constructor and
+ * the given {@code obj} is non-{@code null}, or
+ *
if this reflected object is an instance method or field
+ * and the given {@code obj} is {@code null} or of type
+ * that is not a subclass of the {@link Member#getDeclaringClass()
+ * declaring class} of the member.
+ *
+ *
+ * @since 9
+ * @spec JPMS
+ * @jls 6.6 Access Control
+ * @see #trySetAccessible
+ * @see #setAccessible(boolean)
+ */
+ @CallerSensitive
+ public final boolean canAccess(Object obj) {
+ if (!Member.class.isInstance(this)) {
+ return override;
+ }
+
+ Class> declaringClass = ((Member) this).getDeclaringClass();
+ int modifiers = ((Member) this).getModifiers();
+ if (!Modifier.isStatic(modifiers) &&
+ (this instanceof Method || this instanceof Field)) {
+ if (obj == null) {
+ throw new IllegalArgumentException("null object for " + this);
+ }
+ // if this object is an instance member, the given object
+ // must be a subclass of the declaring class of this reflected object
+ if (!declaringClass.isAssignableFrom(obj.getClass())) {
+ throw new IllegalArgumentException("object is not an instance of "
+ + declaringClass.getName());
+ }
+ } else if (obj != null) {
+ throw new IllegalArgumentException("non-null object for " + this);
+ }
+
+ // access check is suppressed
+ if (override) return true;
+
+ Class> caller = Reflection.getCallerClass();
+ Class> targetClass;
+ if (this instanceof Constructor) {
+ targetClass = declaringClass;
+ } else {
+ targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass();
+ }
+ return Reflection.verifyMemberAccess(caller,
+ declaringClass,
+ targetClass,
+ modifiers);
+ }
+
/**
* Constructor: only used by the Java Virtual Machine.
*/
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java
index f64e84f7f37..968e3f30af4 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java
@@ -168,6 +168,13 @@ public final class Constructor extends Executable {
* is true.
*
* @param flag {@inheritDoc}
+ *
+ * @throws InaccessibleObjectException {@inheritDoc}
+ * @throws SecurityException if the request is denied by the security manager
+ * or this is a constructor for {@code java.lang.Class}
+ *
+ * @since 9
+ * @spec JPMS
*/
@Override
@CallerSensitive
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java
index 05b71785ffa..ef892714b03 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java
@@ -158,6 +158,10 @@ class Field extends AccessibleObject implements Member {
return res;
}
+ /**
+ * @throws InaccessibleObjectException {@inheritDoc}
+ * @throws SecurityException {@inheritDoc}
+ */
@Override
@CallerSensitive
public void setAccessible(boolean flag) {
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java b/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java
index 34db5150f85..b03d449fecc 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java
@@ -30,6 +30,7 @@ package java.lang.reflect;
*
* @see AccessibleObject#setAccessible(boolean)
* @since 9
+ * @spec JPMS
*/
public class InaccessibleObjectException extends RuntimeException {
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
index 9eaf90d0ca8..d6d89980aae 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java
@@ -56,20 +56,19 @@ import sun.security.util.SecurityConstants;
/**
* A layer of modules in the Java virtual machine.
*
- *
A layer is created from a graph of modules that is the {@link
- * Configuration} and a function that maps each module to a {@link ClassLoader}.
+ *
A layer is created from a graph of modules in a {@link Configuration}
+ * and a function that maps each module to a {@link ClassLoader}.
* Creating a layer informs the Java virtual machine about the classes that
- * may be loaded from modules so that the Java virtual machine knows which
- * module that each class is a member of. Each layer, except the {@link
- * #empty() empty} layer, has at least one {@link #parents() parent}.
+ * may be loaded from the modules so that the Java virtual machine knows which
+ * module that each class is a member of.
*
*
Creating a layer creates a {@link Module} object for each {@link
* ResolvedModule} in the configuration. For each resolved module that is
* {@link ResolvedModule#reads() read}, the {@code Module} {@link
* Module#canRead reads} the corresponding run-time {@code Module}, which may
- * be in the same layer or a parent layer. The {@code Module} {@link
- * Module#isExported(String) exports} the packages described by its {@link
- * ModuleDescriptor}.
+ * be in the same layer or a {@link #parents() parent} layer. The {@code Module}
+ * {@link Module#isExported(String) exports} and {@link Module#isOpen(String)
+ * opens} the packages described by its {@link ModuleDescriptor}.
*
*
The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and
* {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods
@@ -80,7 +79,7 @@ import sun.security.util.SecurityConstants;
* a function specified to the method. Each of these methods has an instance
* and static variant. The instance methods create a layer with the receiver
* as the parent layer. The static methods are for more advanced cases where
- * there can be more than one parent layer or a {@link Layer.Controller
+ * there can be more than one parent layer or where a {@link Layer.Controller
* Controller} is needed to control modules in the layer.
*
*
A Java virtual machine has at least one non-empty layer, the {@link
@@ -93,9 +92,8 @@ import sun.security.util.SecurityConstants;
* the {@link #parents() parent} when creating additional layers.
*
*
As when creating a {@code Configuration},
- * {@link ModuleDescriptor#isAutomatic() automatic} modules receive
- * special
- * treatment when creating a layer. An automatic module is created in the
+ * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special
+ * treatment when creating a layer. An automatic module is created in the
* Java virtual machine as a {@code Module} that reads every unnamed {@code
* Module} in the Java virtual machine.
*
@@ -115,8 +113,7 @@ import sun.security.util.SecurityConstants;
*
* Layer parent = Layer.boot();
*
- * Configuration cf = parent.configuration()
- * .resolveRequires(finder, ModuleFinder.of(), Set.of("myapp"));
+ * Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp"));
*
* ClassLoader scl = ClassLoader.getSystemClassLoader();
*
@@ -126,6 +123,7 @@ import sun.security.util.SecurityConstants;
* }
*
* @since 9
+ * @spec JPMS
* @see Module#getLayer()
*/
@@ -168,10 +166,15 @@ public final class Layer {
* module layers return a {@code Controller} that can be used to control
* modules in the layer.
*
+ *
Unless otherwise specified, passing a {@code null} argument to a
+ * method in this class causes a {@link NullPointerException
+ * NullPointerException} to be thrown.
+ *
* @apiNote Care should be taken with {@code Controller} objects, they
* should never be shared with untrusted code.
*
* @since 9
+ * @spec JPMS
*/
public static final class Controller {
private final Layer layer;
@@ -281,10 +284,8 @@ public final class Layer {
* If the parent of the given configuration is not the configuration
* for this layer
* @throws LayerInstantiationException
- * If all modules cannot be defined to the same class loader for any
- * of the reasons listed above or the layer cannot be created because
- * the configuration contains a module named "{@code java.base}" or
- * a module with a package name starting with "{@code java.}"
+ * If the layer cannot be created for any of the reasons specified
+ * by the static {@code defineModulesWithOneLoader} method
* @throws SecurityException
* If {@code RuntimePermission("createClassLoader")} or
* {@code RuntimePermission("getClassLoader")} is denied by
@@ -325,9 +326,8 @@ public final class Layer {
* If the parent of the given configuration is not the configuration
* for this layer
* @throws LayerInstantiationException
- * If the layer cannot be created because the configuration contains
- * a module named "{@code java.base}" or a module with a package
- * name starting with "{@code java.}"
+ * If the layer cannot be created for any of the reasons specified
+ * by the static {@code defineModulesWithManyLoaders} method
* @throws SecurityException
* If {@code RuntimePermission("createClassLoader")} or
* {@code RuntimePermission("getClassLoader")} is denied by
@@ -365,14 +365,8 @@ public final class Layer {
* If the parent of the given configuration is not the configuration
* for this layer
* @throws LayerInstantiationException
- * If creating the {@code Layer} fails for any of the reasons
- * listed above, the layer cannot be created because the
- * configuration contains a module named "{@code java.base}",
- * a module with a package name starting with "{@code java.}" is
- * mapped to a class loader other than the {@link
- * ClassLoader#getPlatformClassLoader() platform class loader},
- * or the function to map a module name to a class loader returns
- * {@code null}
+ * If the layer cannot be created for any of the reasons specified
+ * by the static {@code defineModules} method
* @throws SecurityException
* If {@code RuntimePermission("getClassLoader")} is denied by
* the security manager
@@ -396,7 +390,6 @@ public final class Layer {
* exported to one or more of the modules in this layer. The class
* loader delegates to the class loader of the module, throwing {@code
* ClassNotFoundException} if not found by that class loader.
- *
* When {@code loadClass} is invoked to load classes that do not map to a
* module then it delegates to the parent class loader.
*
@@ -414,6 +407,10 @@ public final class Layer {
*
*
*
+ *
In addition, a layer cannot be created if the configuration contains
+ * a module named "{@code java.base}" or a module with a package name
+ * starting with "{@code java.}".
+ *
*
If there is a security manager then the class loader created by
* this method will load classes and resources with privileges that are
* restricted by the calling context of this method.
@@ -433,9 +430,7 @@ public final class Layer {
* the parent layers, including order
* @throws LayerInstantiationException
* If all modules cannot be defined to the same class loader for any
- * of the reasons listed above or the layer cannot be created because
- * the configuration contains a module named "{@code java.base}" or
- * a module with a package name starting with "{@code java.}"
+ * of the reasons listed above
* @throws SecurityException
* If {@code RuntimePermission("createClassLoader")} or
* {@code RuntimePermission("getClassLoader")} is denied by
@@ -480,7 +475,6 @@ public final class Layer {
* module in a parent layer. The class loader delegates to the class loader
* of the module, throwing {@code ClassNotFoundException} if not found by
* that class loader.
- *
* When {@code loadClass} is invoked to load classes that do not map to a
* module then it delegates to the parent class loader.
*
@@ -533,15 +527,19 @@ public final class Layer {
/**
* Creates a new layer by defining the modules in the given {@code
- * Configuration} to the Java virtual machine.
- * Each module is mapped, by name, to its class loader by means of the
- * given function. The class loader delegation implemented by these class
- * loaders must respect module readability. The class loaders should be
+ * Configuration} to the Java virtual machine. The given function maps each
+ * module in the configuration, by name, to a class loader. Creating the
+ * layer informs the Java virtual machine about the classes that may be
+ * loaded so that the Java virtual machine knows which module that each
+ * class is a member of.
+ *
+ *
The class loader delegation implemented by the class loaders must
+ * respect module readability. The class loaders should be
* {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
* avoid deadlocks during class loading. In addition, the entity creating
- * a new layer with this method should arrange that the class loaders are
+ * a new layer with this method should arrange that the class loaders be
* ready to load from these modules before there are any attempts to load
- * classes or resources.
+ * classes or resources.
*
*
Creating a {@code Layer} can fail for the following reasons:
*
@@ -558,6 +556,13 @@ public final class Layer {
*
*
*
+ *
In addition, a layer cannot be created if the configuration contains
+ * a module named "{@code java.base}", a configuration contains a module
+ * with a package name starting with "{@code java.}" is mapped to a class
+ * loader other than the {@link ClassLoader#getPlatformClassLoader()
+ * platform class loader}, or the function to map a module name to a class
+ * loader returns {@code null}.
+ *
*
If the function to map a module name to class loader throws an error
* or runtime exception then it is propagated to the caller of this method.
*
@@ -565,7 +570,7 @@ public final class Layer {
* @apiNote It is implementation specific as to whether creating a Layer
* with this method is an atomic operation or not. Consequentially it is
* possible for this method to fail with some modules, but not all, defined
- * to Java virtual machine.
+ * to the Java virtual machine.
*
* @param cf
* The configuration for the layer
@@ -580,14 +585,7 @@ public final class Layer {
* If the parent configurations do not match the configuration of
* the parent layers, including order
* @throws LayerInstantiationException
- * If creating the {@code Layer} fails for any of the reasons
- * listed above, the layer cannot be created because the
- * configuration contains a module named "{@code java.base}",
- * a module with a package name starting with "{@code java.}" is
- * mapped to a class loader other than the {@link
- * ClassLoader#getPlatformClassLoader() platform class loader},
- * or the function to map a module name to a class loader returns
- * {@code null}
+ * If creating the layer fails for any of the reasons listed above
* @throws SecurityException
* If {@code RuntimePermission("getClassLoader")} is denied by
* the security manager
@@ -763,7 +761,7 @@ public final class Layer {
/**
* Returns the module with the given name in this layer, or if not in this
- * layer, the {@linkplain #parents parents} layers. Finding a module in
+ * layer, the {@linkplain #parents parent} layers. Finding a module in
* parent layers is equivalent to invoking {@code findModule} on each
* parent, in search order, until the module is found or all parents have
* been searched. In a tree of layers then this is equivalent to
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java b/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java
index ff61c41590f..fbd0de0ac85 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java
@@ -31,6 +31,7 @@ package java.lang.reflect;
* @see Layer
*
* @since 9
+ * @spec JPMS
*/
public class LayerInstantiationException extends RuntimeException {
private static final long serialVersionUID = -906239691613568347L;
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java
index 027a711d3e1..2208a5cbd81 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java
@@ -179,6 +179,10 @@ public final class Method extends Executable {
return res;
}
+ /**
+ * @throws InaccessibleObjectException {@inheritDoc}
+ * @throws SecurityException {@inheritDoc}
+ */
@Override
@CallerSensitive
public void setAccessible(boolean flag) {
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
index 5134b64caf8..e70d9fbb872 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,6 @@ import java.net.URI;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -74,16 +73,15 @@ import sun.security.util.SecurityConstants;
* Java Virtual Machine when a graph of modules is defined to the Java virtual
* machine to create a module {@link Layer Layer}.
*
- *
An unnamed module does not have a name. There is an unnamed module
- * per {@link ClassLoader ClassLoader} that is obtained by invoking the class
- * loader's {@link ClassLoader#getUnnamedModule() getUnnamedModule} method. The
- * {@link Class#getModule() getModule} method of all types defined by a class
- * loader that are not in a named module return the class loader's unnamed
+ *
An unnamed module does not have a name. There is an unnamed module for
+ * each {@link ClassLoader ClassLoader}, obtained by invoking its {@link
+ * ClassLoader#getUnnamedModule() getUnnamedModule} method. All types that are
+ * not in a named module are members of their defining class loader's unnamed
* module.
*
*
The package names that are parameters or returned by methods defined in
* this class are the fully-qualified names of the packages as defined in
- * section 6.5.3 of The Java™ Language Specification , for
+ * section 6.5.3 of The Java™ Language Specification, for
* example, {@code "java.lang"}.
*
*
Unless otherwise specified, passing a {@code null} argument to a method
@@ -91,6 +89,7 @@ import sun.security.util.SecurityConstants;
* be thrown.
*
* @since 9
+ * @spec JPMS
* @see java.lang.Class#getModule
*/
@@ -327,8 +326,9 @@ public final class Module implements AnnotatedElement {
*
* @return this module
*
- * @throws IllegalStateException
- * If this is a named module and the caller is not this module
+ * @throws IllegalCallerException
+ * If this is a named module and the caller's module is not this
+ * module
*
* @see #canRead
*/
@@ -338,7 +338,7 @@ public final class Module implements AnnotatedElement {
if (this.isNamed()) {
Module caller = Reflection.getCallerClass().getModule();
if (caller != this) {
- throw new IllegalStateException(caller + " != " + this);
+ throw new IllegalCallerException(caller + " != " + this);
}
implAddReads(other, true);
}
@@ -533,8 +533,8 @@ public final class Module implements AnnotatedElement {
if (other == this && containsPackage(pn))
return true;
- // all packages in open modules are open
- if (descriptor.isOpen())
+ // all packages in open and automatic modules are open
+ if (descriptor.isOpen() || descriptor.isAutomatic())
return containsPackage(pn);
// exported/opened via module declaration/descriptor
@@ -634,8 +634,7 @@ public final class Module implements AnnotatedElement {
* the given package to the given module.
*
*
This method has no effect if the package is already exported (or
- * open) to the given module. It also has no effect if
- * invoked on an {@link ModuleDescriptor#isOpen open} module.
+ * open) to the given module.
*
* @apiNote As specified in section 5.4.3 of the The Java™
* Virtual Machine Specification , if an attempt to resolve a
@@ -653,8 +652,9 @@ public final class Module implements AnnotatedElement {
* @throws IllegalArgumentException
* If {@code pn} is {@code null}, or this is a named module and the
* package {@code pn} is not a package in this module
- * @throws IllegalStateException
- * If this is a named module and the caller is not this module
+ * @throws IllegalCallerException
+ * If this is a named module and the caller's module is not this
+ * module
*
* @jvms 5.4.3 Resolution
* @see #isExported(String,Module)
@@ -665,10 +665,10 @@ public final class Module implements AnnotatedElement {
throw new IllegalArgumentException("package is null");
Objects.requireNonNull(other);
- if (isNamed() && !descriptor.isOpen()) {
+ if (isNamed()) {
Module caller = Reflection.getCallerClass().getModule();
if (caller != this) {
- throw new IllegalStateException(caller + " != " + this);
+ throw new IllegalCallerException(caller + " != " + this);
}
implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true);
}
@@ -686,8 +686,7 @@ public final class Module implements AnnotatedElement {
* access control checks.
*
*
This method has no effect if the package is already open
- * to the given module. It also has no effect if invoked on an {@link
- * ModuleDescriptor#isOpen open} module.
+ * to the given module.
*
* @param pn
* The package name
@@ -699,9 +698,9 @@ public final class Module implements AnnotatedElement {
* @throws IllegalArgumentException
* If {@code pn} is {@code null}, or this is a named module and the
* package {@code pn} is not a package in this module
- * @throws IllegalStateException
+ * @throws IllegalCallerException
* If this is a named module and this module has not opened the
- * package to at least the caller
+ * package to at least the caller's module
*
* @see #isOpen(String,Module)
* @see AccessibleObject#setAccessible(boolean)
@@ -713,10 +712,10 @@ public final class Module implements AnnotatedElement {
throw new IllegalArgumentException("package is null");
Objects.requireNonNull(other);
- if (isNamed() && !descriptor.isOpen()) {
+ if (isNamed()) {
Module caller = Reflection.getCallerClass().getModule();
if (caller != this && !isOpen(pn, caller))
- throw new IllegalStateException(pn + " is not open to " + caller);
+ throw new IllegalCallerException(pn + " is not open to " + caller);
implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
}
@@ -767,8 +766,8 @@ public final class Module implements AnnotatedElement {
Objects.requireNonNull(other);
Objects.requireNonNull(pn);
- // all packages are open in unnamed and open modules
- if (!isNamed() || descriptor.isOpen())
+ // all packages are open in unnamed, open, and automatic modules
+ if (!isNamed() || descriptor.isOpen() || descriptor.isAutomatic())
return;
// nothing to do if already exported/open to other
@@ -819,17 +818,17 @@ public final class Module implements AnnotatedElement {
* passed a reference to the service type by other code. This method is
* a no-op when invoked on an unnamed module or an automatic module.
*
- *
This method does not cause {@link
- * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be
- * re-run.
+ *
This method does not cause {@link Configuration#resolveAndBind
+ * resolveAndBind} to be re-run.
*
* @param service
* The service type
*
* @return this module
*
- * @throws IllegalStateException
- * If this is a named module and the caller is not this module
+ * @throws IllegalCallerException
+ * If this is a named module and the caller's module is not this
+ * module
*
* @see #canUse(Class)
* @see ModuleDescriptor#uses()
@@ -841,7 +840,7 @@ public final class Module implements AnnotatedElement {
if (isNamed() && !descriptor.isAutomatic()) {
Module caller = Reflection.getCallerClass().getModule();
if (caller != this) {
- throw new IllegalStateException(caller + " != " + this);
+ throw new IllegalCallerException(caller + " != " + this);
}
implAddUses(service);
}
@@ -894,14 +893,13 @@ public final class Module implements AnnotatedElement {
// -- packages --
// Additional packages that are added to the module at run-time.
- // The field is volatile as it may be replaced at run-time
- private volatile Set extraPackages;
+ private volatile Map extraPackages;
private boolean containsPackage(String pn) {
if (descriptor.packages().contains(pn))
return true;
- Set extraPackages = this.extraPackages;
- if (extraPackages != null && extraPackages.contains(pn))
+ Map extraPackages = this.extraPackages;
+ if (extraPackages != null && extraPackages.containsKey(pn))
return true;
return false;
}
@@ -915,7 +913,7 @@ public final class Module implements AnnotatedElement {
* added to the module, dynamic modules
* for example, after it was loaded.
*
- *
For unnamed modules, this method is the equivalent of invoking the
+ *
For unnamed modules, this method is the equivalent to invoking the
* {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of
* this module's class loader and returning the array of package names.
*
@@ -930,12 +928,12 @@ public final class Module implements AnnotatedElement {
if (isNamed()) {
Set packages = descriptor.packages();
- Set extraPackages = this.extraPackages;
+ Map extraPackages = this.extraPackages;
if (extraPackages == null) {
return packages.toArray(new String[0]);
} else {
return Stream.concat(packages.stream(),
- extraPackages.stream())
+ extraPackages.keySet().stream())
.toArray(String[]::new);
}
@@ -955,10 +953,6 @@ public final class Module implements AnnotatedElement {
* Add a package to this module.
*
* @apiNote This method is for Proxy use.
- *
- * @apiNote This is an expensive operation, not expected to be used often.
- * At this time then it does not validate that the package name is a
- * valid java identifier.
*/
void addPackage(String pn) {
implAddPackage(pn, true);
@@ -976,49 +970,52 @@ public final class Module implements AnnotatedElement {
/**
* Add a package to this module.
*
- * If {@code syncVM} is {@code true} then the VM is notified.
+ * If {@code syncVM} is {@code true} then the VM is notified. This method is
+ * a no-op if this is an unnamed module or the module already contains the
+ * package.
+ *
+ * @throws IllegalArgumentException if the package name is not legal
+ * @throws IllegalStateException if the package is defined to another module
*/
private void implAddPackage(String pn, boolean syncVM) {
+ // no-op if unnamed module
if (!isNamed())
- throw new InternalError("adding package to unnamed module?");
- if (descriptor.isOpen())
- throw new InternalError("adding package to open module?");
+ return;
+
+ // no-op if module contains the package
+ if (containsPackage(pn))
+ return;
+
+ // check package name is legal for named modules
if (pn.isEmpty())
- throw new InternalError("adding package to module?");
-
- if (descriptor.packages().contains(pn)) {
- // already in module
- return;
- }
-
- Set extraPackages = this.extraPackages;
- if (extraPackages != null && extraPackages.contains(pn)) {
- // already added
- return;
- }
- synchronized (this) {
- // recheck under lock
- extraPackages = this.extraPackages;
- if (extraPackages != null) {
- if (extraPackages.contains(pn)) {
- // already added
- return;
- }
-
- // copy the set
- extraPackages = new HashSet<>(extraPackages);
- extraPackages.add(pn);
- } else {
- extraPackages = Collections.singleton(pn);
+ throw new IllegalArgumentException("Cannot add package");
+ for (int i=0; i extraPackages = this.extraPackages;
+ if (extraPackages == null) {
+ synchronized (this) {
+ extraPackages = this.extraPackages;
+ if (extraPackages == null)
+ this.extraPackages = extraPackages = new ConcurrentHashMap<>();
+ }
+ }
+
+ // update VM first in case it fails. This is a no-op if another thread
+ // beats us to add the package first
+ if (syncVM) {
+ // throws IllegalStateException if defined to another module
+ addPackage0(this, pn);
+ if (descriptor.isOpen() || descriptor.isAutomatic()) {
+ addExportsToAll0(this, pn);
+ }
+ }
+ extraPackages.putIfAbsent(pn, Boolean.TRUE);
}
@@ -1169,8 +1166,9 @@ public final class Module implements AnnotatedElement {
Map nameToModule,
Module m)
{
- // The VM doesn't know about open modules so need to export all packages
- if (descriptor.isOpen()) {
+ // The VM doesn't special case open or automatic modules so need to
+ // export all packages
+ if (descriptor.isOpen() || descriptor.isAutomatic()) {
assert descriptor.opens().isEmpty();
for (String source : descriptor.packages()) {
addExportsToAll0(m, source);
@@ -1375,35 +1373,44 @@ public final class Module implements AnnotatedElement {
/**
- * Returns an input stream for reading a resource in this module. The
- * {@code name} parameter is a {@code '/'}-separated path name that
- * identifies the resource.
+ * Returns an input stream for reading a resource in this module.
+ * The {@code name} parameter is a {@code '/'}-separated path name that
+ * identifies the resource. As with {@link Class#getResourceAsStream
+ * Class.getResourceAsStream}, this method delegates to the module's class
+ * loader {@link ClassLoader#findResource(String,String)
+ * findResource(String,String)} method, invoking it with the module name
+ * (or {@code null} when the module is unnamed) and the name of the
+ * resource. If the resource name has a leading slash then it is dropped
+ * before delegation.
*
- *
A resource in a named modules may be encapsulated so that
+ *
A resource in a named module may be encapsulated so that
* it cannot be located by code in other modules. Whether a resource can be
- * located or not is determined as follows:
+ * located or not is determined as follows:
*
*
- *
The package name of the resource is derived from the
- * subsequence of characters that precedes the last {@code '/'} and then
- * replacing each {@code '/'} character in the subsequence with
- * {@code '.'}. For example, the package name derived for a resource
- * named "{@code a/b/c/foo.properties}" is "{@code a.b.c}".
+ *
If the resource name ends with "{@code .class}" then it is not
+ * encapsulated.
*
- *
If the package name is a package in the module then the package
- * must be {@link #isOpen open} the module of the caller of this method.
- * If the package is not in the module then the resource is not
- * encapsulated. Resources in the unnamed package or "{@code META-INF}",
- * for example, are never encapsulated because they can never be
- * packages in a named module.
- *
- *
As a special case, resources ending with "{@code .class}" are
- * never encapsulated.
+ *
A package name is derived from the resource name. If
+ * the package name is a {@link #getPackages() package} in the module
+ * then the resource can only be located by the caller of this method
+ * when the package is {@link #isOpen(String,Module) open} to at least
+ * the caller's module. If the resource is not in a package in the module
+ * then the resource is not encapsulated.
*
*
+ *
In the above, the package name for a resource is derived
+ * from the subsequence of characters that precedes the last {@code '/'} in
+ * the name and then replacing each {@code '/'} character in the subsequence
+ * with {@code '.'}. A leading slash is ignored when deriving the package
+ * name. As an example, the package name derived for a resource named
+ * "{@code a/b/c/foo.properties}" is "{@code a.b.c}". A resource name
+ * with the name "{@code META-INF/MANIFEST.MF}" is never encapsulated
+ * because "{@code META-INF}" is not a legal package name.
+ *
*
This method returns {@code null} if the resource is not in this
* module, the resource is encapsulated and cannot be located by the caller,
- * or access to the resource is denied by the security manager.
+ * or access to the resource is denied by the security manager.
*
* @param name
* The resource name
@@ -1413,11 +1420,13 @@ public final class Module implements AnnotatedElement {
* @throws IOException
* If an I/O error occurs
*
- * @see java.lang.module.ModuleReader#open(String)
+ * @see Class#getResourceAsStream(String)
*/
@CallerSensitive
public InputStream getResourceAsStream(String name) throws IOException {
- Objects.requireNonNull(name);
+ if (name.startsWith("/")) {
+ name = name.substring(1);
+ }
if (isNamed() && !ResourceHelper.isSimpleResource(name)) {
Module caller = Reflection.getCallerClass().getModule();
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java
index 15d41a4101d..685aebff39a 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java
@@ -25,6 +25,7 @@
package java.lang.reflect;
+import java.lang.module.ModuleDescriptor;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
@@ -52,6 +53,9 @@ import sun.reflect.misc.ReflectUtil;
import sun.security.action.GetPropertyAction;
import sun.security.util.SecurityConstants;
+import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
+
+
/**
*
* {@code Proxy} provides static methods for creating objects that act like instances
@@ -164,7 +168,8 @@ import sun.security.util.SecurityConstants;
* methods is specified as follows:
*
*
- *
If all the proxy interfaces are in exported packages:
+ *
If all the proxy interfaces are in exported or open
+ * packages:
*
*
if all the proxy interfaces are public, then the proxy class is
* public in a package exported by the
@@ -178,10 +183,11 @@ import sun.security.util.SecurityConstants;
* not possible.
*
*
- *
If at least one proxy interface is a non-exported package:
+ *
If at least one proxy interface is in a package that is
+ * non-exported and non-open:
*
*
if all the proxy interfaces are public, then the proxy class is
- * public in a non-exported package of
+ * public in a non-exported, non-open package of
* dynamic module.
* The names of the package and the module are unspecified.
- * Note that if proxy interfaces with a mix of accessibilities --
- * exported public, exported non-public, non-exported public, non-exported non-public --
- * are proxied by the same instance, then the proxy class's accessibility is
+ * Note that if proxy interfaces with a mix of accessibilities -- for example,
+ * an exported public interface and a non-exported non-public interface -- are
+ * proxied by the same instance, then the proxy class's accessibility is
* governed by the least accessible proxy interface.
*
* Note that it is possible for arbitrary code to obtain access to a proxy class
- * in an exported package with {@link AccessibleObject#setAccessible setAccessible},
- * whereas a proxy class in a non-exported package is never accessible to
+ * in an open package with {@link AccessibleObject#setAccessible setAccessible},
+ * whereas a proxy class in a non-open package is never accessible to
* code outside the module of the proxy class.
*
*
- * Throughout this specification, a "non-exported package" refers to a package that
- * is not exported to all modules. Specifically, it refers to a package that
- * either is not exported at all by its containing module or is exported in a
- * qualified fashion by its containing module.
+ * Throughout this specification, a "non-exported package" refers to a package
+ * that is not exported to all modules, and a "non-open package" refers to
+ * a package that is not open to all modules. Specifically, these terms refer to
+ * a package that either is not exported/open by its containing module or is
+ * exported/open in a qualified fashion by its containing module.
*
*
@@ -272,6 +279,8 @@ import sun.security.util.SecurityConstants;
* @author Peter Jones
* @see InvocationHandler
* @since 1.3
+ * @revised 9
+ * @spec JPMS
*/
public class Proxy implements java.io.Serializable {
private static final long serialVersionUID = -2222568056686623797L;
@@ -358,6 +367,8 @@ public class Proxy implements java.io.Serializable {
* to create a proxy instance instead.
*
* @see Package and Module Membership of Proxy Class
+ * @revised 9
+ * @spec JPMS
*/
@Deprecated
@CallerSensitive
@@ -855,7 +866,11 @@ public class Proxy implements java.io.Serializable {
// create a dynamic module and setup module access
String mn = "jdk.proxy" + counter.incrementAndGet();
String pn = PROXY_PACKAGE_PREFIX + "." + mn;
- Module m = Modules.defineModule(ld, mn, Collections.singleton(pn));
+ ModuleDescriptor descriptor =
+ ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
+ .packages(Set.of(pn))
+ .build();
+ Module m = Modules.defineModule(ld, descriptor, null);
Modules.addReads(m, Proxy.class.getModule());
// java.base to create proxy instance
Modules.addExports(m, pn, Object.class.getModule());
@@ -955,6 +970,8 @@ public class Proxy implements java.io.Serializable {
* {@code null}
*
* @see Package and Module Membership of Proxy Class
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
@@ -1039,6 +1056,9 @@ public class Proxy implements java.io.Serializable {
* @return {@code true} if the class is a proxy class and
* {@code false} otherwise
* @throws NullPointerException if {@code cl} is {@code null}
+ *
+ * @revised 9
+ * @spec JPMS
*/
public static boolean isProxyClass(Class> cl) {
return Proxy.class.isAssignableFrom(cl) && ProxyBuilder.isProxyClass(cl);
diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java b/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java
index c8cb0257b2a..97800b1ce13 100644
--- a/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java
@@ -45,5 +45,7 @@
* members declared by a given class.
*
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
package java.lang.reflect;
diff --git a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java
index 2e52fe2b4e9..d6bd9546750 100644
--- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java
+++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java
@@ -228,6 +228,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
* allow creation of a class loader.
*
* @since 9
+ * @spec JPMS
*/
public URLClassLoader(String name,
URL[] urls,
@@ -262,6 +263,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
* creation of a class loader.
*
* @since 9
+ * @spec JPMS
*/
public URLClassLoader(String name, URL[] urls, ClassLoader parent,
URLStreamHandlerFactory factory) {
@@ -558,6 +560,9 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
* @throws IllegalArgumentException if the package name is
* already defined by this class loader
* @return the newly defined {@code Package} object
+ *
+ * @revised 9
+ * @spec JPMS
*/
protected Package definePackage(String name, Manifest man, URL url) {
String path = name.replace('.', '/').concat("/");
diff --git a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java
index 8f84e10324e..4f0bfa4c27f 100644
--- a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java
+++ b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java
@@ -125,6 +125,7 @@ public class SecureClassLoader extends ClassLoader {
* doesn't allow creation of a class loader.
*
* @since 9
+ * @spec JPMS
*/
protected SecureClassLoader(String name, ClassLoader parent) {
super(name, parent);
diff --git a/jdk/src/java.base/share/classes/java/security/Security.java b/jdk/src/java.base/share/classes/java/security/Security.java
index 49b7e991b40..1076b1d7da7 100644
--- a/jdk/src/java.base/share/classes/java/security/Security.java
+++ b/jdk/src/java.base/share/classes/java/security/Security.java
@@ -25,11 +25,12 @@
package java.security;
-import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.io.*;
import java.net.URL;
+
+import jdk.internal.misc.SharedSecrets;
import sun.security.util.Debug;
import sun.security.util.PropertyExpander;
@@ -800,9 +801,6 @@ public final class Security {
* "package.definition", we need to signal to the SecurityManager
* class that the value has just changed, and that it should
* invalidate it's local cache values.
- *
- * Rather than create a new API entry for this function,
- * we use reflection to set a private variable.
*/
private static void invalidateSMCache(String key) {
@@ -810,42 +808,8 @@ public final class Security {
final boolean pd = key.equals("package.definition");
if (pa || pd) {
- AccessController.doPrivileged(new PrivilegedAction<>() {
- public Void run() {
- try {
- /* Get the class via the bootstrap class loader. */
- Class> cl = Class.forName(
- "java.lang.SecurityManager", false, null);
- Field f = null;
- boolean accessible = false;
-
- if (pa) {
- f = cl.getDeclaredField("packageAccessValid");
- accessible = f.isAccessible();
- f.setAccessible(true);
- } else {
- f = cl.getDeclaredField("packageDefinitionValid");
- accessible = f.isAccessible();
- f.setAccessible(true);
- }
- f.setBoolean(f, false);
- f.setAccessible(accessible);
- }
- catch (Exception e1) {
- /* If we couldn't get the class, it hasn't
- * been loaded yet. If there is no such
- * field, we shouldn't try to set it. There
- * shouldn't be a security execption, as we
- * are loaded by boot class loader, and we
- * are inside a doPrivileged() here.
- *
- * NOOP: don't do anything...
- */
- }
- return null;
- } /* run */
- }); /* PrivilegedAction */
- } /* if */
+ SharedSecrets.getJavaLangAccess().invalidatePackageAccessCache();
+ }
}
private static void check(String directive) {
diff --git a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
index 600b1810a2e..b587da9b9e3 100644
--- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
+++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java
@@ -350,6 +350,8 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
* @see MissingResourceException
* @see ResourceBundleProvider
* @since 1.1
+ * @revised 9
+ * @spec JPMS
*/
public abstract class ResourceBundle {
@@ -870,6 +872,8 @@ public abstract class ResourceBundle {
* @throws UnsupportedOperationException
* if this method is called in a named module
* @since 1.6
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static final ResourceBundle getBundle(String baseName,
@@ -938,6 +942,7 @@ public abstract class ResourceBundle {
* specified module
* @return a resource bundle for the given base name and the default locale
* @since 9
+ * @spec JPMS
* @see ResourceBundleProvider
*/
@CallerSensitive
@@ -991,6 +996,7 @@ public abstract class ResourceBundle {
* be found in the specified {@code module}
* @return a resource bundle for the given base name and locale in the module
* @since 9
+ * @spec JPMS
*/
@CallerSensitive
public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) {
@@ -1036,6 +1042,8 @@ public abstract class ResourceBundle {
* @throws UnsupportedOperationException
* if this method is called in a named module
* @since 1.6
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
@@ -1243,6 +1251,8 @@ public abstract class ResourceBundle {
* @exception MissingResourceException
* if no resource bundle for the specified base name can be found
* @since 1.2
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static ResourceBundle getBundle(String baseName, Locale locale,
@@ -1465,6 +1475,8 @@ public abstract class ResourceBundle {
* @throws UnsupportedOperationException
* if this method is called in a named module
* @since 1.6
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static ResourceBundle getBundle(String baseName, Locale targetLocale,
@@ -2194,6 +2206,8 @@ public abstract class ResourceBundle {
* by the caller's module.
*
* @since 1.6
+ * @revised 9
+ * @spec JPMS
* @see ResourceBundle.Control#getTimeToLive(String,Locale)
*/
@CallerSensitive
@@ -2475,6 +2489,8 @@ public abstract class ResourceBundle {
* of {@link ResourceBundleControlProvider} are ignored in named modules.
*
* @since 1.6
+ * @revised 9
+ * @spec JPMS
* @see java.util.spi.ResourceBundleProvider
*/
public static class Control {
@@ -3103,6 +3119,8 @@ public abstract class ResourceBundle {
* if an error occurred when reading resources using
* any I/O operations
* @see java.util.spi.ResourceBundleProvider#getBundle(String, Locale)
+ * @revised 9
+ * @spec JPMS
*/
public ResourceBundle newBundle(String baseName, Locale locale, String format,
ClassLoader loader, boolean reload)
diff --git a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
index 0b437d44e2e..6ffb6177e39 100644
--- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
+++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java
@@ -119,7 +119,7 @@ import jdk.internal.reflect.Reflection;
* and deployed as an explicit module must have an appropriate uses
* clause in its module descriptor to declare that the module uses
* implementations of the service. A corresponding requirement is that a
- * provider deployed as a named module must have an appropriate
+ * provider deployed as an explicit module must have an appropriate
* provides clause in its module descriptor to declare that the module
* provides an implementation of the service. The uses and
* provides allow consumers of a service to be linked to modules
@@ -203,8 +203,11 @@ import jdk.internal.reflect.Reflection;
* ordering of modules in a layer, is not defined.
*
*
If a named module declares more than one provider then the providers
- * are located in the order that they appear in the {@code provides} table of
- * the {@code Module} class file attribute ({@code module-info.class}).
+ * are located in the iteration order of the {@link
+ * java.lang.module.ModuleDescriptor.Provides#providers() providers} list.
+ * Providers added dynamically by instrumentation agents ({@link
+ * java.lang.instrument.Instrumentation#redefineModule redefineModule})
+ * are always located after providers declared by the module.
*
*
When locating providers in unnamed modules then the ordering is
* based on the order that the class loader's {@link
@@ -335,6 +338,8 @@ import jdk.internal.reflect.Reflection;
*
* @author Mark Reinhold
* @since 1.6
+ * @revised 9
+ * @spec JPMS
*/
public final class ServiceLoader
@@ -386,6 +391,7 @@ public final class ServiceLoader
*
* @param The service type
* @since 9
+ * @spec JPMS
*/
public static interface Provider extends Supplier {
/**
@@ -927,26 +933,28 @@ public final class ServiceLoader
} else {
catalog = ServicesCatalog.getServicesCatalogOrNull(loader);
}
- Stream stream1;
+ List providers;
if (catalog == null) {
- stream1 = Stream.empty();
+ providers = List.of();
} else {
- stream1 = catalog.findServices(serviceName).stream();
+ providers = catalog.findServices(serviceName);
}
// modules in custom layers that define modules to the class loader
- Stream stream2;
if (loader == null) {
- stream2 = Stream.empty();
+ return providers.iterator();
} else {
+ List allProviders = new ArrayList<>(providers);
Layer bootLayer = Layer.boot();
- stream2 = JLRM_ACCESS.layers(loader)
- .filter(l -> (l != bootLayer))
- .map(l -> providers(l))
- .flatMap(List::stream);
+ Iterator iterator = JLRM_ACCESS.layers(loader).iterator();
+ while (iterator.hasNext()) {
+ Layer layer = iterator.next();
+ if (layer != bootLayer) {
+ allProviders.addAll(providers(layer));
+ }
+ }
+ return allProviders.iterator();
}
-
- return Stream.concat(stream1, stream2).iterator();
}
@Override
@@ -1214,6 +1222,9 @@ public final class ServiceLoader
*
* @return An iterator that lazily loads providers for this loader's
* service
+ *
+ * @revised 9
+ * @spec JPMS
*/
public Iterator iterator() {
@@ -1279,8 +1290,10 @@ public final class ServiceLoader
* provider to be loaded.
*
*
If this loader's provider caches are cleared by invoking the {@link
- * #reload() reload} method then existing streams for this service
- * loader should be discarded.
+ * #reload() reload} method then existing streams for this service loader
+ * should be discarded. The returned stream's source {@code Spliterator} is
+ * fail-fast and will throw {@link ConcurrentModificationException}
+ * if the provider cache has been cleared.
*
*
The following examples demonstrate usage. The first example
* creates a stream of providers, the second example is the same except
@@ -1300,6 +1313,7 @@ public final class ServiceLoader
* @return A stream that lazily loads providers for this loader's service
*
* @since 9
+ * @spec JPMS
*/
public Stream> stream() {
// use cached providers as the source when all providers loaded
@@ -1414,6 +1428,9 @@ public final class ServiceLoader
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
+ *
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static ServiceLoader load(Class service,
@@ -1457,6 +1474,9 @@ public final class ServiceLoader
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
+ *
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static ServiceLoader load(Class service) {
@@ -1490,6 +1510,9 @@ public final class ServiceLoader
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
+ *
+ * @revised 9
+ * @spec JPMS
*/
@CallerSensitive
public static ServiceLoader loadInstalled(Class service) {
@@ -1522,6 +1545,7 @@ public final class ServiceLoader
* not declare that it uses {@code service}
*
* @since 9
+ * @spec JPMS
*/
@CallerSensitive
public static ServiceLoader load(Layer layer, Class service) {
@@ -1551,6 +1575,7 @@ public final class ServiceLoader
* or error is thrown when locating or instantiating the provider.
*
* @since 9
+ * @spec JPMS
*/
public Optional findFirst() {
Iterator iterator = iterator();
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
index c549dbdb30f..330f4fb78a3 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
@@ -40,6 +40,7 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.security.AccessController;
import java.security.AccessControlContext;
+import java.security.Permission;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
@@ -132,24 +133,30 @@ import java.util.concurrent.locks.LockSupport;
*
*
*
- *
The common pool is by default constructed with default
- * parameters, but these may be controlled by setting the following
- * {@linkplain System#getProperty system properties}:
+ *
The parameters used to construct the common pool may be controlled by
+ * setting the following {@linkplain System#getProperty system properties}:
*
*
{@code java.util.concurrent.ForkJoinPool.common.parallelism}
* - the parallelism level, a non-negative integer
*
{@code java.util.concurrent.ForkJoinPool.common.threadFactory}
- * - the class name of a {@link ForkJoinWorkerThreadFactory}
+ * - the class name of a {@link ForkJoinWorkerThreadFactory}.
+ * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
+ * is used to load this class.
*
{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler}
- * - the class name of a {@link UncaughtExceptionHandler}
+ * - the class name of a {@link UncaughtExceptionHandler}.
+ * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
+ * is used to load this class.
*
{@code java.util.concurrent.ForkJoinPool.common.maximumSpares}
* - the maximum number of allowed extra threads to maintain target
* parallelism (default 256).
*
- * If a {@link SecurityManager} is present and no factory is
- * specified, then the default pool uses a factory supplying
- * threads that have no {@link Permissions} enabled.
- * The system class loader is used to load these classes.
+ * If no thread factory is supplied via a system property, then the
+ * common pool uses a factory that uses the system class loader as the
+ * {@linkplain Thread#getContextClassLoader() thread context class loader}.
+ * In addition, if a {@link SecurityManager} is present, then
+ * the common pool uses a factory supplying threads that have no
+ * {@link Permissions} enabled.
+ *
* Upon any error in establishing these settings, default parameters
* are used. It is possible to disable or limit the use of threads in
* the common pool by setting the parallelism property to zero, and/or
@@ -638,20 +645,38 @@ public class ForkJoinPool extends AbstractExecutorService {
*
* @param pool the pool this thread works in
* @return the new worker thread, or {@code null} if the request
- * to create a thread is rejected.
+ * to create a thread is rejected
* @throws NullPointerException if the pool is null
*/
public ForkJoinWorkerThread newThread(ForkJoinPool pool);
}
+ static AccessControlContext contextWithPermissions(Permission ... perms) {
+ Permissions permissions = new Permissions();
+ for (Permission perm : perms)
+ permissions.add(perm);
+ return new AccessControlContext(
+ new ProtectionDomain[] { new ProtectionDomain(null, permissions) });
+ }
+
/**
* Default ForkJoinWorkerThreadFactory implementation; creates a
- * new ForkJoinWorkerThread.
+ * new ForkJoinWorkerThread using the system class loader as the
+ * thread context class loader.
*/
private static final class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
+ private static final AccessControlContext ACC = contextWithPermissions(
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"));
+
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
- return new ForkJoinWorkerThread(pool);
+ return AccessController.doPrivileged(
+ new PrivilegedAction<>() {
+ public ForkJoinWorkerThread run() {
+ return new ForkJoinWorkerThread(
+ pool, ClassLoader.getSystemClassLoader()); }},
+ ACC);
}
}
@@ -3244,26 +3269,20 @@ public class ForkJoinPool extends AbstractExecutorService {
* An ACC to restrict permissions for the factory itself.
* The constructed workers have no permissions set.
*/
- private static final AccessControlContext INNOCUOUS_ACC;
- static {
- Permissions innocuousPerms = new Permissions();
- innocuousPerms.add(modifyThreadPermission);
- innocuousPerms.add(new RuntimePermission(
- "enableContextClassLoaderOverride"));
- innocuousPerms.add(new RuntimePermission(
- "modifyThreadGroup"));
- INNOCUOUS_ACC = new AccessControlContext(new ProtectionDomain[] {
- new ProtectionDomain(null, innocuousPerms)
- });
- }
+ private static final AccessControlContext ACC = contextWithPermissions(
+ modifyThreadPermission,
+ new RuntimePermission("enableContextClassLoaderOverride"),
+ new RuntimePermission("modifyThreadGroup"),
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"));
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
- return AccessController.doPrivileged(new PrivilegedAction<>() {
- public ForkJoinWorkerThread run() {
- return new ForkJoinWorkerThread.
- InnocuousForkJoinWorkerThread(pool);
- }}, INNOCUOUS_ACC);
+ return AccessController.doPrivileged(
+ new PrivilegedAction<>() {
+ public ForkJoinWorkerThread run() {
+ return new ForkJoinWorkerThread.
+ InnocuousForkJoinWorkerThread(pool); }},
+ ACC);
}
}
-
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
index 93bb08dd48f..a3054b865ba 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
@@ -36,6 +36,8 @@
package java.util.concurrent;
import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
/**
@@ -87,12 +89,27 @@ public class ForkJoinWorkerThread extends Thread {
this.workQueue = pool.registerWorker(this);
}
+ /**
+ * Version for use by the default pool. Supports setting the
+ * context class loader. This is a separate constructor to avoid
+ * affecting the protected constructor.
+ */
+ ForkJoinWorkerThread(ForkJoinPool pool, ClassLoader ccl) {
+ super("aForkJoinWorkerThread");
+ super.setContextClassLoader(ccl);
+ this.pool = pool;
+ this.workQueue = pool.registerWorker(this);
+ }
+
/**
* Version for InnocuousForkJoinWorkerThread.
*/
- ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
+ ForkJoinWorkerThread(ForkJoinPool pool,
+ ClassLoader ccl,
+ ThreadGroup threadGroup,
AccessControlContext acc) {
super(threadGroup, null, "aForkJoinWorkerThread");
+ super.setContextClassLoader(ccl);
ThreadLocalRandom.setInheritedAccessControlContext(this, acc);
ThreadLocalRandom.eraseThreadLocals(this); // clear before registering
this.pool = pool;
@@ -179,20 +196,21 @@ public class ForkJoinWorkerThread extends Thread {
/**
* A worker thread that has no permissions, is not a member of any
- * user-defined ThreadGroup, and erases all ThreadLocals after
+ * user-defined ThreadGroup, uses the system class loader as
+ * thread context class loader, and erases all ThreadLocals after
* running each top-level task.
*/
static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
/** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
private static final ThreadGroup innocuousThreadGroup =
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<>() {
- public ThreadGroup run() {
- ThreadGroup group = Thread.currentThread().getThreadGroup();
- for (ThreadGroup p; (p = group.getParent()) != null; )
- group = p;
- return new ThreadGroup(group, "InnocuousForkJoinWorkerThreadGroup");
- }});
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<>() {
+ public ThreadGroup run() {
+ ThreadGroup group = Thread.currentThread().getThreadGroup();
+ for (ThreadGroup p; (p = group.getParent()) != null; )
+ group = p;
+ return new ThreadGroup(group, "InnocuousForkJoinWorkerThreadGroup");
+ }});
/** An AccessControlContext supporting no privileges */
private static final AccessControlContext INNOCUOUS_ACC =
@@ -202,7 +220,10 @@ public class ForkJoinWorkerThread extends Thread {
});
InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
- super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
+ super(pool,
+ ClassLoader.getSystemClassLoader(),
+ innocuousThreadGroup,
+ INNOCUOUS_ACC);
}
@Override // to erase ThreadLocals
@@ -210,11 +231,6 @@ public class ForkJoinWorkerThread extends Thread {
ThreadLocalRandom.eraseThreadLocals(this);
}
- @Override // to always report system loader
- public ClassLoader getContextClassLoader() {
- return ClassLoader.getSystemClassLoader();
- }
-
@Override // to silently fail
public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
diff --git a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java
index 06b6c266c89..b0cba4f4915 100644
--- a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java
+++ b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java
@@ -81,6 +81,7 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
* ResourceBundleProvider Service Providers
*
* @since 9
+ * @spec JPMS
*/
public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider {
private static final JavaUtilResourceBundleAccess RB_ACCESS =
diff --git a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java
index f74830b4d6a..871d9192ec0 100644
--- a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java
+++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java
@@ -44,6 +44,8 @@ import java.util.ResourceBundle;
*
* @author Masayoshi Okutsu
* @since 1.8
+ * @revised 9
+ * @spec JPMS
* @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control)
* ResourceBundle.getBundle
* @see java.util.ServiceLoader#load(Class)
diff --git a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java
index 0074ae32090..251831f1dcb 100644
--- a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java
+++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java
@@ -57,6 +57,7 @@ import java.util.ResourceBundle;
* @see
* ResourceBundleProvider Service Providers
* @since 9
+ * @spec JPMS
*/
public interface ResourceBundleProvider {
/**
diff --git a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
index 34e99dfdd9b..289a80fdca6 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
@@ -186,7 +186,7 @@ public class JmodFile implements AutoCloseable {
public Entry getEntry(Section section, String name) {
String entry = section.jmodDir() + "/" + name;
ZipEntry ze = zipfile.getEntry(entry);
- return (ze != null) ? new Entry(ze) : null;
+ return (ze == null || ze.isDirectory()) ? null : new Entry(ze);
}
/**
@@ -201,7 +201,7 @@ public class JmodFile implements AutoCloseable {
{
String entry = section.jmodDir() + "/" + name;
ZipEntry e = zipfile.getEntry(entry);
- if (e == null) {
+ if (e == null || e.isDirectory()) {
throw new IOException(name + " not found: " + file);
}
return zipfile.getInputStream(e);
diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
index ab052ec0b30..a0886e82080 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
@@ -57,8 +57,9 @@ import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.stream.Stream;
-import jdk.internal.module.ModulePatcher.PatchedModuleReader;
import jdk.internal.misc.VM;
+import jdk.internal.module.ModulePatcher.PatchedModuleReader;
+import jdk.internal.module.SystemModules;
/**
@@ -135,7 +136,7 @@ public class BuiltinClassLoader
// maps package name to loaded module for modules in the boot layer
private static final Map packageToModule
- = new ConcurrentHashMap<>(1024);
+ = new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER);
// maps a module name to a module reference
private final Map nameToModule;
@@ -922,13 +923,13 @@ public class BuiltinClassLoader
* Returns the ModuleReader for the given module.
*/
private ModuleReader moduleReaderFor(ModuleReference mref) {
- return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref));
+ return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader);
}
/**
* Creates a ModuleReader for the given module.
*/
- private ModuleReader createModuleReader(ModuleReference mref) {
+ private static ModuleReader createModuleReader(ModuleReference mref) {
try {
return mref.open();
} catch (IOException e) {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java
index a9e0750391a..18a42b7b6f3 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,10 @@
*/
package jdk.internal.loader;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
import jdk.internal.module.Checks;
/**
@@ -34,7 +38,8 @@ public final class ResourceHelper {
private ResourceHelper() { }
/**
- * Returns the package name for a resource.
+ * Returns the package name for a resource or the empty package if
+ * the resource name does not contain a slash.
*/
public static String getPackageName(String name) {
int index = name.lastIndexOf('/');
@@ -46,19 +51,75 @@ public final class ResourceHelper {
}
/**
- * Returns true if the resource is a simple resource that can
- * never be encapsulated. Resources ending in "{@code .class}" or where
- * the package name is not a Java identifier are resources that can
- * never be encapsulated.
+ * Returns true if the resource is a simple resource. Simple
+ * resources can never be encapsulated. Resources ending in "{@code .class}"
+ * or where the package name is not a legal package name can not be
+ * encapsulated.
*/
public static boolean isSimpleResource(String name) {
int len = name.length();
if (len > 6 && name.endsWith(".class")) {
return true;
}
- if (!Checks.isJavaIdentifier(getPackageName(name))) {
+ if (!Checks.isPackageName(getPackageName(name))) {
return true;
}
return false;
}
+
+ /**
+ * Converts a resource name to a file path. Returns {@code null} if the
+ * resource name cannot be converted into a file path. Resource names
+ * with empty elements, or elements that are "." or ".." are rejected,
+ * as is a resource name that translates to a file path with a root
+ * component.
+ */
+ public static Path toFilePath(String name) {
+ // scan the resource name to eagerly reject obviously invalid names
+ int next;
+ int off = 0;
+ while ((next = name.indexOf('/', off)) != -1) {
+ int len = next - off;
+ if (!mayTranslate(name, off, len)) {
+ return null;
+ }
+ off = next + 1;
+ }
+ int rem = name.length() - off;
+ if (!mayTranslate(name, off, rem)) {
+ return null;
+ }
+
+ // convert to file path
+ Path path;
+ if (File.separatorChar == '/') {
+ path = Paths.get(name);
+ } else {
+ // not allowed to embed file separators
+ if (name.contains(File.separator))
+ return null;
+ path = Paths.get(name.replace('/', File.separatorChar));
+ }
+
+ // file path not allowed to have root component
+ return (path.getRoot() == null) ? path : null;
+ }
+
+ /**
+ * Returns {@code true} if the element in a resource name is a candidate
+ * to translate to the element of a file path.
+ */
+ private static boolean mayTranslate(String name, int off, int len) {
+ if (len <= 2) {
+ if (len == 0)
+ return false;
+ boolean starsWithDot = (name.charAt(off) == '.');
+ if (len == 1 && starsWithDot)
+ return false;
+ if (len == 2 && starsWithDot && (name.charAt(off+1) == '.'))
+ return false;
+ }
+ return true;
+ }
+
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
index 6838111c35d..7cb2c1e74a4 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java
@@ -174,4 +174,9 @@ public interface JavaLangAccess {
* Invokes Long.fastUUID
*/
String fastUUID(long lsb, long msb);
+
+ /**
+ * Invalidate package access cache
+ */
+ void invalidatePackageAccessCache();
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
index eed7a2d2aff..53e8b4c82c7 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -59,20 +59,21 @@ public interface JavaLangModuleAccess {
*/
ModuleDescriptor.Builder newModuleBuilder(String mn,
boolean strict,
- boolean open,
- boolean synthetic);
+ Set ms);
/**
- * Returns the set of packages that are exported (unconditionally or
- * unconditionally).
+ * Returns a snapshot of the packages in the module.
*/
- Set exportedPackages(ModuleDescriptor.Builder builder);
+ Set packages(ModuleDescriptor.Builder builder);
/**
- * Returns the set of packages that are opened (unconditionally or
- * unconditionally).
+ * Adds a dependence on a module with the given (possibly un-parsable)
+ * version string.
*/
- Set openPackages(ModuleDescriptor.Builder builder);
+ void requires(ModuleDescriptor.Builder builder,
+ Set ms,
+ String mn,
+ String compiledVersion);
/**
* Returns a {@code ModuleDescriptor.Requires} of the given modifiers
@@ -113,24 +114,12 @@ public interface JavaLangModuleAccess {
*/
Provides newProvides(String service, List providers);
- /**
- * Returns a {@code ModuleDescriptor.Version} of the given version.
- */
- Version newVersion(String v);
-
- /**
- * Clones the given module descriptor with an augmented set of packages
- */
- ModuleDescriptor newModuleDescriptor(ModuleDescriptor md, Set pkgs);
-
/**
* Returns a new {@code ModuleDescriptor} instance.
*/
ModuleDescriptor newModuleDescriptor(String name,
Version version,
- boolean open,
- boolean automatic,
- boolean synthetic,
+ Set ms,
Set requires,
Set exports,
Set opens,
@@ -148,9 +137,9 @@ public interface JavaLangModuleAccess {
* and the empty configuration as the parent. The post resolution
* checks are optionally run.
*/
- Configuration resolveRequiresAndUses(ModuleFinder finder,
- Collection roots,
- boolean check,
- PrintStream traceOutput);
+ Configuration resolveAndBind(ModuleFinder finder,
+ Collection roots,
+ boolean check,
+ PrintStream traceOutput);
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
index 2ef9c11d248..9196f39ff77 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,7 @@ import jdk.internal.misc.JavaLangModuleAccess;
import jdk.internal.misc.SharedSecrets;
/**
- * This builder is optimized for reconstituting ModuleDescriptor
+ * This builder is optimized for reconstituting the {@code ModuleDescriptor}s
* for system modules. The validation should be done at jlink time.
*
* 1. skip name validation
@@ -136,9 +136,7 @@ final class Builder {
}
final String name;
- boolean open;
- boolean automatic;
- boolean synthetic;
+ boolean open, synthetic, mandated;
Set requires;
Set exports;
Set opens;
@@ -165,13 +163,13 @@ final class Builder {
return this;
}
- Builder automatic(boolean value) {
- this.automatic = value;
+ Builder synthetic(boolean value) {
+ this.synthetic = value;
return this;
}
- Builder synthetic(boolean value) {
- this.synthetic = value;
+ Builder mandated(boolean value) {
+ this.mandated = value;
return this;
}
@@ -228,13 +226,10 @@ final class Builder {
*
* @throws IllegalArgumentException if {@code v} is null or cannot be
* parsed as a version string
- * @throws IllegalStateException if the module version is already set
*
* @see Version#parse(String)
*/
public Builder version(String v) {
- if (version != null)
- throw new IllegalStateException("module version already set");
Version ver = cachedVersion;
if (ver != null && v.equals(ver.toString())) {
version = ver;
@@ -246,63 +241,63 @@ final class Builder {
/**
* Sets the module main class.
- *
- * @throws IllegalStateException if already set
*/
public Builder mainClass(String mc) {
- if (mainClass != null)
- throw new IllegalStateException("main class already set");
mainClass = mc;
return this;
}
/**
* Sets the OS name.
- *
- * @throws IllegalStateException if already set
*/
public Builder osName(String name) {
- if (osName != null)
- throw new IllegalStateException("OS name already set");
this.osName = name;
return this;
}
/**
* Sets the OS arch.
- *
- * @throws IllegalStateException if already set
*/
public Builder osArch(String arch) {
- if (osArch != null)
- throw new IllegalStateException("OS arch already set");
this.osArch = arch;
return this;
}
/**
* Sets the OS version.
- *
- * @throws IllegalStateException if already set
*/
public Builder osVersion(String version) {
- if (osVersion != null)
- throw new IllegalStateException("OS version already set");
this.osVersion = version;
return this;
}
+ /**
+ * Returns an immutable set of the module modifiers derived from the flags.
+ */
+ private Set modifiers() {
+ int n = 0;
+ if (open) n++;
+ if (synthetic) n++;
+ if (mandated) n++;
+ if (n == 0) {
+ return Collections.emptySet();
+ } else {
+ ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n];
+ if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN;
+ if (synthetic) mods[--n] = ModuleDescriptor.Modifier.SYNTHETIC;
+ if (mandated) mods[--n] = ModuleDescriptor.Modifier.MANDATED;
+ return Set.of(mods);
+ }
+ }
+
/**
* Builds a {@code ModuleDescriptor} from the components.
*/
public ModuleDescriptor build(int hashCode) {
assert name != null;
-
return JLMA.newModuleDescriptor(name,
version,
- open,
- automatic,
- synthetic,
+ modifiers(),
requires,
exports,
opens,
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
index 2fdeaab6211..e19e6528ce0 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
package jdk.internal.module;
/**
- * Utility class for checking module name and binary names.
+ * Utility class for checking module, package, and class names.
*/
public final class Checks {
@@ -58,8 +58,6 @@ public final class Checks {
throw new IllegalArgumentException(name + ": Invalid module name"
+ ": '" + id + "' is not a Java identifier");
}
- //if (!Character.isJavaIdentifierStart(last))
- // throw new IllegalArgumentException(name + ": Module name ends in digit");
return name;
}
@@ -77,8 +75,6 @@ public final class Checks {
int last = isJavaIdentifier(name, off, name.length() - off);
if (last == -1)
return false;
- //if (!Character.isJavaIdentifierStart(last))
- // return false;
return true;
}
@@ -89,40 +85,62 @@ public final class Checks {
* package name
*/
public static String requirePackageName(String name) {
- return requireBinaryName("package name", name);
+ return requireTypeName("package name", name);
}
/**
- * Checks a name to ensure that it's a legal type name.
+ * Returns {@code true} if the given name is a legal package name.
+ */
+ public static boolean isPackageName(String name) {
+ return isTypeName(name);
+ }
+
+ /**
+ * Checks a name to ensure that it's a legal qualified class name
*
* @throws IllegalArgumentException if name is null or not a legal
- * type name
+ * qualified class name
*/
public static String requireServiceTypeName(String name) {
- return requireBinaryName("service type name", name);
+ return requireQualifiedClassName("service type name", name);
}
/**
- * Checks a name to ensure that it's a legal type name.
+ * Checks a name to ensure that it's a legal qualified class name.
*
* @throws IllegalArgumentException if name is null or not a legal
- * type name
+ * qualified class name
*/
public static String requireServiceProviderName(String name) {
- return requireBinaryName("service provider name", name);
+ return requireQualifiedClassName("service provider name", name);
}
/**
- * Returns {@code true} if the given name is a legal binary name.
+ * Checks a name to ensure that it's a legal qualified class name in
+ * a named package.
+ *
+ * @throws IllegalArgumentException if name is null or not a legal
+ * qualified class name in a named package
*/
- public static boolean isJavaIdentifier(String name) {
- return isBinaryName(name);
+ public static String requireQualifiedClassName(String what, String name) {
+ requireTypeName(what, name);
+ if (name.indexOf('.') == -1)
+ throw new IllegalArgumentException(name + ": is not a qualified name of"
+ + " a Java class in a named package");
+ return name;
}
/**
- * Returns {@code true} if the given name is a legal binary name.
+ * Returns {@code true} if the given name is a legal class name.
*/
- public static boolean isBinaryName(String name) {
+ public static boolean isClassName(String name) {
+ return isTypeName(name);
+ }
+
+ /**
+ * Returns {@code true} if the given name is a legal type name.
+ */
+ private static boolean isTypeName(String name) {
int next;
int off = 0;
while ((next = name.indexOf('.', off)) != -1) {
@@ -135,12 +153,12 @@ public final class Checks {
}
/**
- * Checks if the given name is a legal binary name.
+ * Checks if the given name is a legal type name.
*
* @throws IllegalArgumentException if name is null or not a legal
- * binary name
+ * type name
*/
- public static String requireBinaryName(String what, String name) {
+ private static String requireTypeName(String what, String name) {
if (name == null)
throw new IllegalArgumentException("Null " + what);
int next;
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
index 69c7ee670dd..fc3c3904850 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
package jdk.internal.module;
import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
import java.lang.module.ModuleDescriptor.Requires;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
@@ -98,14 +99,17 @@ public final class ClassFileAttributes {
// module_flags
int module_flags = cr.readUnsignedShort(off);
- boolean open = ((module_flags & ACC_OPEN) != 0);
- boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
off += 2;
- ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn,
- false,
- open,
- synthetic);
+ Set modifiers = new HashSet<>();
+ if ((module_flags & ACC_OPEN) != 0)
+ modifiers.add(ModuleDescriptor.Modifier.OPEN);
+ if ((module_flags & ACC_SYNTHETIC) != 0)
+ modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
+ if ((module_flags & ACC_MANDATED) != 0)
+ modifiers.add(ModuleDescriptor.Modifier.MANDATED);
+
+ Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
// module_version
String module_version = cr.readUTF8(off, buf);
@@ -142,19 +146,13 @@ public final class ClassFileAttributes {
mods.add(Requires.Modifier.MANDATED);
}
-
// requires_version
- Version compiledVersion = null;
String requires_version = cr.readUTF8(off, buf);
off += 2;
- if (requires_version != null) {
- compiledVersion = Version.parse(requires_version);
- }
-
- if (compiledVersion == null) {
+ if (requires_version == null) {
builder.requires(mods, dn);
} else {
- builder.requires(mods, dn, compiledVersion);
+ JLMA.requires(builder, mods, dn, requires_version);
}
}
@@ -283,11 +281,14 @@ public final class ClassFileAttributes {
attr.putShort(module_name_index);
// module_flags
+ Set modifiers = descriptor.modifiers();
int module_flags = 0;
- if (descriptor.isOpen())
+ if (modifiers.contains(ModuleDescriptor.Modifier.OPEN))
module_flags |= ACC_OPEN;
- if (descriptor.isSynthetic())
+ if (modifiers.contains(ModuleDescriptor.Modifier.SYNTHETIC))
module_flags |= ACC_SYNTHETIC;
+ if (modifiers.contains(ModuleDescriptor.Modifier.MANDATED))
+ module_flags |= ACC_MANDATED;
attr.putShort(module_flags);
// module_version
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java
index 48fe536c7aa..66e241ee555 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,8 +46,8 @@ public class ClassFileConstants {
// access, requires, exports, and opens flags
public static final int ACC_MODULE = 0x8000;
public static final int ACC_OPEN = 0x0020;
- public static final int ACC_TRANSITIVE = 0x0010;
- public static final int ACC_STATIC_PHASE = 0x0020;
+ public static final int ACC_TRANSITIVE = 0x0020;
+ public static final int ACC_STATIC_PHASE = 0x0040;
public static final int ACC_SYNTHETIC = 0x1000;
public static final int ACC_MANDATED = 0x8000;
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
index 71406460c41..6fe2e7423b7 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
+import java.util.stream.Stream;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.BuiltinClassLoader;
@@ -114,7 +115,12 @@ public final class ModuleBootstrap {
long t0 = System.nanoTime();
// system modules (may be patched)
- ModuleFinder systemModules = ModuleFinder.ofSystem();
+ ModuleFinder systemModules;
+ if (SystemModules.MODULE_NAMES.length > 0) {
+ systemModules = SystemModuleFinder.getInstance();
+ } else {
+ systemModules = ModuleFinder.ofSystem();
+ }
PerfCounters.systemModulesTime.addElapsedTimeFrom(t0);
@@ -275,10 +281,10 @@ public final class ModuleBootstrap {
// run the resolver to create the configuration
Configuration cf = SharedSecrets.getJavaLangModuleAccess()
- .resolveRequiresAndUses(finder,
- roots,
- needPostResolutionChecks,
- traceOutput);
+ .resolveAndBind(finder,
+ roots,
+ needPostResolutionChecks,
+ traceOutput);
// time to create configuration
PerfCounters.resolveTime.addElapsedTimeFrom(t3);
@@ -318,20 +324,20 @@ public final class ModuleBootstrap {
// if needed check that there are no split packages in the set of
// resolved modules for the boot layer
if (SystemModules.hasSplitPackages() || needPostResolutionChecks) {
- Map packageToModule = new HashMap<>();
- for (ResolvedModule resolvedModule : cf.modules()) {
- ModuleDescriptor descriptor =
- resolvedModule.reference().descriptor();
- String name = descriptor.name();
- for (String p : descriptor.packages()) {
- String other = packageToModule.putIfAbsent(p, name);
- if (other != null) {
- fail("Package " + p + " in both module "
- + name + " and module " + other);
- }
+ Map packageToModule = new HashMap<>();
+ for (ResolvedModule resolvedModule : cf.modules()) {
+ ModuleDescriptor descriptor =
+ resolvedModule.reference().descriptor();
+ String name = descriptor.name();
+ for (String p : descriptor.packages()) {
+ String other = packageToModule.putIfAbsent(p, name);
+ if (other != null) {
+ fail("Package " + p + " in both module "
+ + name + " and module " + other);
}
}
}
+ }
long t4 = System.nanoTime();
@@ -380,10 +386,9 @@ public final class ModuleBootstrap {
Set otherMods)
{
// resolve all root modules
- Configuration cf = Configuration.empty()
- .resolveRequires(finder,
- ModuleFinder.of(),
- roots);
+ Configuration cf = Configuration.empty().resolve(finder,
+ ModuleFinder.of(),
+ roots);
// module name -> reference
Map map = new HashMap<>();
@@ -416,7 +421,7 @@ public final class ModuleBootstrap {
/**
* Creates a finder from the module path that is the value of the given
- * system property.
+ * system property and optionally patched by --patch-module
*/
private static ModuleFinder createModulePathFinder(String prop) {
String s = System.getProperty(prop);
@@ -429,7 +434,7 @@ public final class ModuleBootstrap {
for (String dir: dirs) {
paths[i++] = Paths.get(dir);
}
- return ModuleFinder.of(paths);
+ return ModulePath.of(patcher, paths);
}
}
@@ -528,6 +533,7 @@ public final class ModuleBootstrap {
if (!extraOpens.isEmpty()) {
addExtraExportsOrOpens(bootLayer, extraOpens, true);
}
+
}
private static void addExtraExportsOrOpens(Layer bootLayer,
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
index 3aac651577c..b58c717affe 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,6 @@ import java.lang.module.ModuleDescriptor.Builder;
import java.lang.module.ModuleDescriptor.Requires;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
-import java.lang.module.ModuleDescriptor.Version;
import java.nio.ByteBuffer;
import java.nio.BufferUnderflowException;
import java.util.ArrayList;
@@ -51,7 +50,6 @@ import java.util.function.Supplier;
import jdk.internal.misc.JavaLangModuleAccess;
import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.ModuleResolution;
import static jdk.internal.module.ClassFileConstants.*;
@@ -221,7 +219,7 @@ public final class ModuleInfo {
Set attributes = new HashSet<>();
Builder builder = null;
- Set packages = null;
+ Set allPackages = null;
String mainClass = null;
String[] osValues = null;
ModuleHashes hashes = null;
@@ -245,7 +243,7 @@ public final class ModuleInfo {
break;
case MODULE_PACKAGES :
- packages = readModulePackagesAttribute(in, cpool);
+ allPackages = readModulePackagesAttribute(in, cpool);
break;
case MODULE_MAIN_CLASS :
@@ -284,51 +282,44 @@ public final class ModuleInfo {
throw invalidModuleDescriptor(MODULE + " attribute not found");
}
+ // ModuleMainClass and ModuleTarget attributes
+ if (mainClass != null) {
+ builder.mainClass(mainClass);
+ }
+ if (osValues != null) {
+ if (osValues[0] != null) builder.osName(osValues[0]);
+ if (osValues[1] != null) builder.osArch(osValues[1]);
+ if (osValues[2] != null) builder.osVersion(osValues[2]);
+ }
+
// If the ModulePackages attribute is not present then the packageFinder
// is used to find the set of packages
boolean usedPackageFinder = false;
- if (packages == null && packageFinder != null) {
+ if (allPackages == null && packageFinder != null) {
try {
- packages = new HashSet<>(packageFinder.get());
+ allPackages = packageFinder.get();
} catch (UncheckedIOException x) {
throw x.getCause();
}
usedPackageFinder = true;
}
- if (packages != null) {
- Set exportedPackages = JLMA.exportedPackages(builder);
- Set openPackages = JLMA.openPackages(builder);
- if (packages.containsAll(exportedPackages)
- && packages.containsAll(openPackages)) {
- packages.removeAll(exportedPackages);
- packages.removeAll(openPackages);
- } else {
- // the set of packages is not complete
- Set exportedAndOpenPackages = new HashSet<>();
- exportedAndOpenPackages.addAll(exportedPackages);
- exportedAndOpenPackages.addAll(openPackages);
- for (String pn : exportedAndOpenPackages) {
- if (!packages.contains(pn)) {
- String tail;
- if (usedPackageFinder) {
- tail = " not found by package finder";
- } else {
- tail = " missing from ModulePackages attribute";
- }
- throw invalidModuleDescriptor("Package " + pn + tail);
- }
+ if (allPackages != null) {
+ Set knownPackages = JLMA.packages(builder);
+ if (!allPackages.containsAll(knownPackages)) {
+ Set missingPackages = new HashSet<>(knownPackages);
+ missingPackages.removeAll(allPackages);
+ assert !missingPackages.isEmpty();
+ String missingPackage = missingPackages.iterator().next();
+ String tail;
+ if (usedPackageFinder) {
+ tail = " not found in module";
+ } else {
+ tail = " missing from ModulePackages class file attribute";
}
- assert false; // should not get here
- }
- builder.contains(packages);
- }
+ throw invalidModuleDescriptor("Package " + missingPackage + tail);
- if (mainClass != null)
- builder.mainClass(mainClass);
- if (osValues != null) {
- if (osValues[0] != null) builder.osName(osValues[0]);
- if (osValues[1] != null) builder.osArch(osValues[1]);
- if (osValues[2] != null) builder.osVersion(osValues[2]);
+ }
+ builder.packages(allPackages);
}
ModuleDescriptor descriptor = builder.build();
@@ -347,10 +338,17 @@ public final class ModuleInfo {
String mn = cpool.getModuleName(module_name_index);
int module_flags = in.readUnsignedShort();
- boolean open = ((module_flags & ACC_OPEN) != 0);
- boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
- Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic);
+ Set modifiers = new HashSet<>();
+ boolean open = ((module_flags & ACC_OPEN) != 0);
+ if (open)
+ modifiers.add(ModuleDescriptor.Modifier.OPEN);
+ if ((module_flags & ACC_SYNTHETIC) != 0)
+ modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
+ if ((module_flags & ACC_MANDATED) != 0)
+ modifiers.add(ModuleDescriptor.Modifier.MANDATED);
+
+ Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
int module_version_index = in.readUnsignedShort();
if (module_version_index != 0) {
@@ -381,16 +379,11 @@ public final class ModuleInfo {
}
int requires_version_index = in.readUnsignedShort();
- Version compiledVersion = null;
- if (requires_version_index != 0) {
- String vs = cpool.getUtf8(requires_version_index);
- compiledVersion = Version.parse(vs);
- }
-
- if (compiledVersion == null) {
+ if (requires_version_index == 0) {
builder.requires(mods, dn);
} else {
- builder.requires(mods, dn, compiledVersion);
+ String vs = cpool.getUtf8(requires_version_index);
+ JLMA.requires(builder, mods, dn, vs);
}
if (dn.equals("java.base"))
@@ -629,10 +622,7 @@ public final class ModuleInfo {
/**
* Return true if the given attribute name is the name of a pre-defined
- * attribute that is not allowed in the class file.
- *
- * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
- * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
+ * attribute in JVMS 4.7 that is not allowed in a module-info class.
*/
private static boolean isAttributeDisallowed(String name) {
Set notAllowed = predefinedNotAllowed;
@@ -640,6 +630,7 @@ public final class ModuleInfo {
notAllowed = Set.of(
"ConstantValue",
"Code",
+ "Deprecated",
"StackMapTable",
"Exceptions",
"EnclosingMethod",
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
index 0d05ad296e9..73fb660ed7f 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
@@ -56,7 +56,7 @@ public final class ModuleInfoExtender {
// the packages in the ModulePackages attribute
private Set packages;
- // the value of the module_version in Module attribute
+ // the value for the module version in the Module attribute
private Version version;
// the value of the ModuleMainClass attribute
@@ -78,7 +78,11 @@ public final class ModuleInfoExtender {
}
/**
- * Sets the set of packages for the ModulePackages attribute
+ * Sets the packages for the ModulePackages attribute
+ *
+ * @apiNote This method does not check that the package names are legal
+ * package names or that the set of packages is a super set of the
+ * packages in the module.
*/
public ModuleInfoExtender packages(Set packages) {
this.packages = Collections.unmodifiableSet(packages);
@@ -86,7 +90,7 @@ public final class ModuleInfoExtender {
}
/**
- * Sets the value of the module_version in Module attribute.
+ * Sets the value for the module version in the Module attribute
*/
public ModuleInfoExtender version(Version version) {
this.version = version;
@@ -95,6 +99,9 @@ public final class ModuleInfoExtender {
/**
* Sets the value of the ModuleMainClass attribute.
+ *
+ * @apiNote This method does not check that the main class is a legal
+ * class name in a named package.
*/
public ModuleInfoExtender mainClass(String mainClass) {
this.mainClass = mainClass;
@@ -133,7 +140,7 @@ public final class ModuleInfoExtender {
/**
* A ClassVisitor that supports adding class file attributes. If an
- * attribute already exists then the first occurence of the attribute
+ * attribute already exists then the first occurrence of the attribute
* is replaced.
*/
private static class AttributeAddingClassVisitor extends ClassVisitor {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
index 9c3308f97a0..15e60d0d611 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,13 +41,6 @@ import jdk.internal.loader.ClassLoaders;
* are generated at build time.
*/
final class ModuleLoaderMap {
- /*
- * The list of boot modules and platform modules are generated at build time.
- */
- private static final String[] BOOT_MODULES
- = new String[] { "@@BOOT_MODULE_NAMES@@" };
- private static final String[] PLATFORM_MODULES
- = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
/**
* Returns the function to map modules in the given configuration to the
@@ -55,6 +48,10 @@ final class ModuleLoaderMap {
*/
static Function mappingFunction(Configuration cf) {
+ // The list of boot modules and platform modules are generated at build time.
+ final String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
+ final String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
+
Set bootModules = new HashSet<>(BOOT_MODULES.length);
for (String mn : BOOT_MODULES) {
bootModules.add(mn);
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
index 5bd7ef5ed04..fe3f8930ad2 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
import java.net.MalformedURLException;
@@ -54,6 +55,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.loader.Resource;
+import jdk.internal.loader.ResourceHelper;
import jdk.internal.misc.JavaLangModuleAccess;
import jdk.internal.misc.SharedSecrets;
import sun.net.www.ParseUtil;
@@ -108,8 +110,11 @@ public final class ModulePatcher {
if (paths == null)
return mref;
- // scan the JAR file or directory tree to get the set of packages
+ // Scan the JAR file or directory tree to get the set of packages.
+ // For automatic modules then packages that do not contain class files
+ // must be ignored.
Set packages = new HashSet<>();
+ boolean isAutomatic = descriptor.isAutomatic();
try {
for (Path file : paths) {
if (Files.isRegularFile(file)) {
@@ -118,8 +123,10 @@ public final class ModulePatcher {
// is not supported by the boot class loader
try (JarFile jf = new JarFile(file.toFile())) {
jf.stream()
+ .filter(e -> !e.isDirectory()
+ && (!isAutomatic || e.getName().endsWith(".class")))
.map(e -> toPackageName(file, e))
- .filter(Checks::isJavaIdentifier)
+ .filter(Checks::isPackageName)
.forEach(packages::add);
}
@@ -129,8 +136,10 @@ public final class ModulePatcher {
Path top = file;
Files.find(top, Integer.MAX_VALUE,
((path, attrs) -> attrs.isRegularFile()))
+ .filter(path -> !isAutomatic
+ || path.toString().endsWith(".class"))
.map(path -> toPackageName(top, path))
- .filter(Checks::isJavaIdentifier)
+ .filter(Checks::isPackageName)
.forEach(packages::add);
}
@@ -141,10 +150,30 @@ public final class ModulePatcher {
}
// if there are new packages then we need a new ModuleDescriptor
- Set original = descriptor.packages();
- packages.addAll(original);
- if (packages.size() > original.size()) {
- descriptor = JLMA.newModuleDescriptor(descriptor, packages);
+ packages.removeAll(descriptor.packages());
+ if (!packages.isEmpty()) {
+ Builder builder = JLMA.newModuleBuilder(descriptor.name(),
+ /*strict*/ false,
+ descriptor.modifiers());
+ if (!descriptor.isAutomatic()) {
+ descriptor.requires().forEach(builder::requires);
+ descriptor.exports().forEach(builder::exports);
+ descriptor.opens().forEach(builder::opens);
+ descriptor.uses().forEach(builder::uses);
+ }
+ descriptor.provides().forEach(builder::provides);
+
+ descriptor.version().ifPresent(builder::version);
+ descriptor.mainClass().ifPresent(builder::mainClass);
+ descriptor.osName().ifPresent(builder::osName);
+ descriptor.osArch().ifPresent(builder::osArch);
+ descriptor.osVersion().ifPresent(builder::osVersion);
+
+ // original + new packages
+ builder.packages(descriptor.packages());
+ builder.packages(packages);
+
+ descriptor = builder.build();
}
// return a module reference to the patched module
@@ -471,23 +500,14 @@ public final class ModulePatcher {
@Override
public Resource find(String name) throws IOException {
- Path file = Paths.get(name.replace('/', File.separatorChar));
- if (file.getRoot() == null) {
- file = dir.resolve(file);
- } else {
- // drop the root component so that the resource is
- // located relative to the module directory
- int n = file.getNameCount();
- if (n == 0)
- return null;
- file = dir.resolve(file.subpath(0, n));
- }
-
- if (Files.isRegularFile(file)) {
- return newResource(name, dir, file);
- } else {
- return null;
+ Path path = ResourceHelper.toFilePath(name);
+ if (path != null) {
+ Path file = dir.resolve(path);
+ if (Files.isRegularFile(file)) {
+ return newResource(name, dir, file);
+ }
}
+ return null;
}
private Resource newResource(String name, Path top, Path file) {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
index fb7871d3c31..ae337423965 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ import java.io.UncheckedIOException;
import java.lang.module.FindException;
import java.lang.module.InvalidModuleDescriptorException;
import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Requires;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.net.URI;
@@ -70,12 +69,11 @@ import jdk.internal.util.jar.VersionedStream;
/**
* A {@code ModuleFinder} that locates modules on the file system by searching
- * a sequence of directories or packaged modules.
- *
- * The {@code ModuleFinder} can be created to work in either the run-time
- * or link-time phases. In both cases it locates modular JAR and exploded
- * modules. When created for link-time then it additionally locates
- * modules in JMOD files.
+ * a sequence of directories or packaged modules. The ModuleFinder can be
+ * created to work in either the run-time or link-time phases. In both cases it
+ * locates modular JAR and exploded modules. When created for link-time then it
+ * additionally locates modules in JMOD files. The ModuleFinder can also
+ * optionally patch any modules that it locates with a ModulePatcher.
*/
public class ModulePath implements ModuleFinder {
@@ -87,6 +85,9 @@ public class ModulePath implements ModuleFinder {
// true for the link phase (supports modules packaged in JMOD format)
private final boolean isLinkPhase;
+ // for patching modules, can be null
+ private final ModulePatcher patcher;
+
// the entries on this module path
private final Path[] entries;
private int next;
@@ -94,19 +95,51 @@ public class ModulePath implements ModuleFinder {
// map of module name to module reference map for modules already located
private final Map cachedModules = new HashMap<>();
- public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
+
+ private ModulePath(Runtime.Version version,
+ boolean isLinkPhase,
+ ModulePatcher patcher,
+ Path... entries) {
this.releaseVersion = version;
this.isLinkPhase = isLinkPhase;
+ this.patcher = patcher;
this.entries = entries.clone();
for (Path entry : this.entries) {
Objects.requireNonNull(entry);
}
}
- public ModulePath(Path... entries) {
- this(JarFile.runtimeVersion(), false, entries);
+ /**
+ * Returns a ModuleFinder that that locates modules on the file system by
+ * searching a sequence of directories and/or packaged modules. The modules
+ * may be patched by the given ModulePatcher.
+ */
+ public static ModuleFinder of(ModulePatcher patcher, Path... entries) {
+ return new ModulePath(JarFile.runtimeVersion(), false, patcher, entries);
}
+ /**
+ * Returns a ModuleFinder that that locates modules on the file system by
+ * searching a sequence of directories and/or packaged modules.
+ */
+ public static ModuleFinder of(Path... entries) {
+ return of((ModulePatcher)null, entries);
+ }
+
+ /**
+ * Returns a ModuleFinder that that locates modules on the file system by
+ * searching a sequence of directories and/or packaged modules.
+ *
+ * @param version The release version to use for multi-release JAR files
+ * @param isLinkPhase {@code true} if the link phase to locate JMOD files
+ */
+ public static ModuleFinder of(Runtime.Version version,
+ boolean isLinkPhase,
+ Path... entries) {
+ return new ModulePath(version, isLinkPhase, null, entries);
+ }
+
+
@Override
public Optional find(String name) {
Objects.requireNonNull(name);
@@ -195,8 +228,7 @@ public class ModulePath implements ModuleFinder {
if (attrs.isDirectory()) {
Path mi = entry.resolve(MODULE_INFO);
if (!Files.exists(mi)) {
- // does not exist or unable to determine so assume a
- // directory of modules
+ // assume a directory of modules
return scanDirectory(entry);
}
}
@@ -206,11 +238,17 @@ public class ModulePath implements ModuleFinder {
if (mref != null) {
String name = mref.descriptor().name();
return Collections.singletonMap(name, mref);
- } else {
- // skipped
- return Collections.emptyMap();
}
+ // not recognized
+ String msg;
+ if (!isLinkPhase && entry.toString().endsWith(".jmod")) {
+ msg = "JMOD format not supported at execution time";
+ } else {
+ msg = "Module format not recognized";
+ }
+ throw new FindException(msg + ": " + entry);
+
} catch (IOException ioe) {
throw new FindException(ioe);
}
@@ -266,14 +304,11 @@ public class ModulePath implements ModuleFinder {
/**
- * Locates a packaged or exploded module, returning a {@code ModuleReference}
- * to the module. Returns {@code null} if the entry is skipped because it is
- * to a directory that does not contain a module-info.class or it's a hidden
- * file.
+ * Reads a packaged or exploded module, returning a {@code ModuleReference}
+ * to the module. Returns {@code null} if the entry is not recognized.
*
* @throws IOException if an I/O error occurs
- * @throws FindException if the file is not recognized as a module or an
- * error occurs parsing its module descriptor
+ * @throws FindException if an error occurs parsing its module descriptor
*/
private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
throws IOException
@@ -282,24 +317,16 @@ public class ModulePath implements ModuleFinder {
if (attrs.isDirectory()) {
return readExplodedModule(entry); // may return null
- }
-
- String fn = entry.getFileName().toString();
- if (attrs.isRegularFile()) {
- if (fn.endsWith(".jar")) {
- return readJar(entry);
- } else if (fn.endsWith(".jmod")) {
- if (isLinkPhase)
- return readJMod(entry);
- throw new FindException("JMOD files not supported: " + entry);
- }
- }
-
- // skip hidden files
- if (fn.startsWith(".") || Files.isHidden(entry)) {
- return null;
} else {
- throw new FindException("Unrecognized module: " + entry);
+ String fn = entry.getFileName().toString();
+ if (attrs.isRegularFile()) {
+ if (fn.endsWith(".jar")) {
+ return readJar(entry);
+ } else if (isLinkPhase && fn.endsWith(".jmod")) {
+ return readJMod(entry);
+ }
+ }
+ return null;
}
} catch (InvalidModuleDescriptorException e) {
@@ -327,7 +354,7 @@ public class ModulePath implements ModuleFinder {
}
}
- // -- jmod files --
+ // -- JMOD files --
private Set jmodPackages(JmodFile jf) {
return jf.stream()
@@ -339,7 +366,7 @@ public class ModulePath implements ModuleFinder {
}
/**
- * Returns a {@code ModuleReference} to a module in jmod file on the
+ * Returns a {@code ModuleReference} to a module in JMOD file on the
* file system.
*
* @throws IOException
@@ -362,7 +389,7 @@ public class ModulePath implements ModuleFinder {
/**
* Returns the service type corresponding to the name of a services
- * configuration file if it is a valid Java identifier.
+ * configuration file if it is a legal type name.
*
* For example, if called with "META-INF/services/p.S" then this method
* returns a container with the value "p.S".
@@ -374,7 +401,7 @@ public class ModulePath implements ModuleFinder {
String prefix = cf.substring(0, index);
if (prefix.equals(SERVICES_PREFIX)) {
String sn = cf.substring(index);
- if (Checks.isJavaIdentifier(sn))
+ if (Checks.isClassName(sn))
return Optional.of(sn);
}
}
@@ -403,11 +430,10 @@ public class ModulePath implements ModuleFinder {
*
* 1. The module name (and optionally the version) is derived from the file
* name of the JAR file
- * 2. All packages are exported and open
- * 3. It has no non-exported/non-open packages
- * 4. The contents of any META-INF/services configuration files are mapped
+ * 2. All packages are derived from the .class files in the JAR file
+ * 3. The contents of any META-INF/services configuration files are mapped
* to "provides" declarations
- * 5. The Main-Class attribute in the main attributes of the JAR manifest
+ * 4. The Main-Class attribute in the main attributes of the JAR manifest
* is mapped to the module descriptor mainClass
*/
private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
@@ -443,9 +469,7 @@ public class ModulePath implements ModuleFinder {
mn = cleanModuleName(mn);
// Builder throws IAE if module name is empty or invalid
- ModuleDescriptor.Builder builder
- = ModuleDescriptor.automaticModule(mn)
- .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
+ ModuleDescriptor.Builder builder = ModuleDescriptor.newAutomaticModule(mn);
if (vs != null)
builder.version(vs);
@@ -453,17 +477,22 @@ public class ModulePath implements ModuleFinder {
Map> map = VersionedStream.stream(jf)
.filter(e -> !e.isDirectory())
.map(JarEntry::getName)
+ .filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX)))
.collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
Collectors.toSet()));
- Set resources = map.get(Boolean.FALSE);
+ Set classFiles = map.get(Boolean.FALSE);
Set configFiles = map.get(Boolean.TRUE);
- // all packages are exported and open
- resources.stream()
+
+ // the packages containing class files
+ Set packages = classFiles.stream()
.map(this::toPackageName)
.flatMap(Optional::stream)
.distinct()
- .forEach(pn -> builder.exports(pn).opens(pn));
+ .collect(Collectors.toSet());
+
+ // all packages are exported and open
+ builder.packages(packages);
// map names of service configuration files to service names
Set serviceNames = configFiles.stream()
@@ -481,6 +510,11 @@ public class ModulePath implements ModuleFinder {
String cn;
while ((cn = nextLine(reader)) != null) {
if (cn.length() > 0) {
+ String pn = packageName(cn);
+ if (!packages.contains(pn)) {
+ String msg = "Provider class " + cn + " not in module";
+ throw new IOException(msg);
+ }
providerClasses.add(cn);
}
}
@@ -494,8 +528,15 @@ public class ModulePath implements ModuleFinder {
if (man != null) {
Attributes attrs = man.getMainAttributes();
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
- if (mainClass != null)
- builder.mainClass(mainClass.replace("/", "."));
+ if (mainClass != null) {
+ mainClass = mainClass.replace("/", ".");
+ String pn = packageName(mainClass);
+ if (!packages.contains(pn)) {
+ String msg = "Main-Class " + mainClass + " not in module";
+ throw new IOException(msg);
+ }
+ builder.mainClass(mainClass);
+ }
}
return builder.build();
@@ -569,10 +610,10 @@ public class ModulePath implements ModuleFinder {
try {
ModuleDescriptor md = deriveModuleDescriptor(jf);
attrs = new ModuleInfo.Attributes(md, null, null);
- } catch (IllegalArgumentException iae) {
+ } catch (IllegalArgumentException e) {
throw new FindException(
"Unable to derive module descriptor for: "
- + jf.getName(), iae);
+ + jf.getName(), e);
}
} else {
@@ -580,7 +621,7 @@ public class ModulePath implements ModuleFinder {
() -> jarPackages(jf));
}
- return ModuleReferences.newJarModule(attrs, file);
+ return ModuleReferences.newJarModule(attrs, patcher, file);
}
}
@@ -617,7 +658,15 @@ public class ModulePath implements ModuleFinder {
// for now
return null;
}
- return ModuleReferences.newExplodedModule(attrs, dir);
+ return ModuleReferences.newExplodedModule(attrs, patcher, dir);
+ }
+
+ /**
+ * Maps a type name to its package name.
+ */
+ private static String packageName(String cn) {
+ int index = cn.lastIndexOf('.');
+ return (index == -1) ? "" : cn.substring(0, index);
}
/**
@@ -629,19 +678,18 @@ public class ModulePath implements ModuleFinder {
*/
private Optional toPackageName(String name) {
assert !name.endsWith("/");
-
int index = name.lastIndexOf("/");
if (index == -1) {
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
throw new IllegalArgumentException(name
- + " found in top-level directory:"
+ + " found in top-level directory"
+ " (unnamed package not allowed in module)");
}
return Optional.empty();
}
String pn = name.substring(0, index).replace('/', '.');
- if (Checks.isJavaIdentifier(pn)) {
+ if (Checks.isPackageName(pn)) {
return Optional.of(pn);
} else {
// not a valid package name
@@ -654,7 +702,7 @@ public class ModulePath implements ModuleFinder {
* name.
*
* @throws IllegalArgumentException if the name is a class file in
- * the top-level directory (and it's not module-info.class)
+ * the top-level directory (and it's not module-info.class)
*/
private Optional toPackageName(Path file) {
assert file.getRoot() == null;
@@ -664,14 +712,14 @@ public class ModulePath implements ModuleFinder {
String name = file.toString();
if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
throw new IllegalArgumentException(name
- + " found in in top-level directory"
+ + " found in top-level directory"
+ " (unnamed package not allowed in module)");
}
return Optional.empty();
}
String pn = parent.toString().replace(File.separatorChar, '.');
- if (Checks.isJavaIdentifier(pn)) {
+ if (Checks.isPackageName(pn)) {
return Optional.of(pn);
} else {
// not a valid package name
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java
index 2ab42bdb4a2..f861b294aef 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java
@@ -163,7 +163,14 @@ public class ModuleReferenceImpl extends ModuleReference {
@Override
public String toString() {
- return super.toString();
+ StringBuilder sb = new StringBuilder();
+ sb.append("[module ");
+ sb.append(descriptor().name());
+ sb.append(", location=");
+ sb.append(location().orElseThrow(() -> new InternalError()));
+ if (isPatched()) sb.append(" (patched)");
+ sb.append("]");
+ return sb.toString();
}
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
index a2aff8f76be..2e2af727599 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
@@ -36,7 +36,6 @@ import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -51,7 +50,7 @@ import java.util.stream.Stream;
import java.util.zip.ZipFile;
import jdk.internal.jmod.JmodFile;
-import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.loader.ResourceHelper;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.module.ModuleHashes.HashSupplier;
import jdk.internal.util.jar.VersionedStream;
@@ -65,20 +64,16 @@ import sun.net.www.ParseUtil;
*/
class ModuleReferences {
-
- private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
-
private ModuleReferences() { }
/**
- * Creates a ModuleReference to a module or to patched module when
- * creating modules for the boot Layer and --patch-module is specified.
+ * Creates a ModuleReference to a possibly-patched module
*/
private static ModuleReference newModule(ModuleInfo.Attributes attrs,
URI uri,
Supplier supplier,
+ ModulePatcher patcher,
HashSupplier hasher) {
-
ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(),
uri,
supplier,
@@ -86,38 +81,42 @@ class ModuleReferences {
attrs.recordedHashes(),
hasher,
attrs.moduleResolution());
- if (JLA.getBootLayer() == null)
- mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+ if (patcher != null)
+ mref = patcher.patchIfNeeded(mref);
return mref;
}
/**
- * Creates a ModuleReference to a module packaged as a modular JAR.
+ * Creates a ModuleReference to a possibly-patched module in a modular JAR.
*/
- static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) {
+ static ModuleReference newJarModule(ModuleInfo.Attributes attrs,
+ ModulePatcher patcher,
+ Path file) {
URI uri = file.toUri();
Supplier supplier = () -> new JarModuleReader(file, uri);
HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
- return newModule(attrs, uri, supplier, hasher);
+ return newModule(attrs, uri, supplier, patcher, hasher);
}
/**
- * Creates a ModuleReference to a module packaged as a JMOD.
+ * Creates a ModuleReference to a module in a JMOD file.
*/
static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
URI uri = file.toUri();
Supplier supplier = () -> new JModModuleReader(file, uri);
HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
- return newModule(attrs, uri, supplier, hasher);
+ return newModule(attrs, uri, supplier, null, hasher);
}
/**
- * Creates a ModuleReference to an exploded module.
+ * Creates a ModuleReference to a possibly-patched exploded module.
*/
- static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) {
+ static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs,
+ ModulePatcher patcher,
+ Path dir) {
Supplier supplier = () -> new ExplodedModuleReader(dir);
- return newModule(attrs, dir.toUri(), supplier, null);
+ return newModule(attrs, dir.toUri(), supplier, patcher, null);
}
@@ -243,7 +242,8 @@ class ModuleReferences {
}
private JarEntry getEntry(String name) {
- return jf.getJarEntry(Objects.requireNonNull(name));
+ JarEntry entry = jf.getJarEntry(Objects.requireNonNull(name));
+ return (entry == null || entry.isDirectory()) ? null : entry;
}
@Override
@@ -369,21 +369,6 @@ class ModuleReferences {
}
}
- /**
- * Returns a Path to access to the given resource.
- */
- private Path toPath(String name) {
- Path path = Paths.get(name.replace('/', File.separatorChar));
- if (path.getRoot() == null) {
- return dir.resolve(path);
- } else {
- // drop the root component so that the resource is
- // located relative to the module directory
- int n = path.getNameCount();
- return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
- }
- }
-
/**
* Throws IOException if the module reader is closed;
*/
@@ -391,11 +376,27 @@ class ModuleReferences {
if (closed) throw new IOException("ModuleReader is closed");
}
+ /**
+ * Returns a Path to access the given resource. Returns null if the
+ * resource name does not convert to a file path that locates a regular
+ * file in the module.
+ */
+ private Path toFilePath(String name) {
+ Path path = ResourceHelper.toFilePath(name);
+ if (path != null) {
+ Path file = dir.resolve(path);
+ if (Files.isRegularFile(file)) {
+ return file;
+ }
+ }
+ return null;
+ }
+
@Override
public Optional find(String name) throws IOException {
ensureOpen();
- Path path = toPath(name);
- if (path != null && Files.isRegularFile(path)) {
+ Path path = toFilePath(name);
+ if (path != null) {
try {
return Optional.of(path.toUri());
} catch (IOError e) {
@@ -409,8 +410,8 @@ class ModuleReferences {
@Override
public Optional open(String name) throws IOException {
ensureOpen();
- Path path = toPath(name);
- if (path != null && Files.isRegularFile(path)) {
+ Path path = toFilePath(name);
+ if (path != null) {
return Optional.of(Files.newInputStream(path));
} else {
return Optional.empty();
@@ -420,8 +421,8 @@ class ModuleReferences {
@Override
public Optional read(String name) throws IOException {
ensureOpen();
- Path path = toPath(name);
- if (path != null && Files.isRegularFile(path)) {
+ Path path = toFilePath(name);
+ if (path != null) {
return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
} else {
return Optional.empty();
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
index 9f68cfbc421..485d2e130b5 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
@@ -82,8 +82,8 @@ public class Modules {
String name,
Set packages)
{
- ModuleDescriptor descriptor = ModuleDescriptor.module(name)
- .contains(packages)
+ ModuleDescriptor descriptor = ModuleDescriptor.newModule(name)
+ .packages(packages)
.build();
return JLRMA.defineModule(loader, descriptor, null);
@@ -185,7 +185,8 @@ public class Modules {
/**
* Adds a package to a module's content.
*
- * This method is a no-op if the module already contains the package.
+ * This method is a no-op if the module already contains the package or the
+ * module is an unnamed module.
*/
public static void addPackage(Module m, String pn) {
JLRMA.addPackage(m, pn);
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java
index 5ec0a62ca69..a7ee7ffe74f 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java
@@ -80,8 +80,6 @@ public class SystemModuleFinder implements ModuleFinder {
= PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
private static final PerfCounter exportsCount
= PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
- // ImageReader used to access all modules in the image
- private static final ImageReader imageReader;
// singleton finder to find modules in the run-time images
private static final SystemModuleFinder INSTANCE;
@@ -96,13 +94,28 @@ public class SystemModuleFinder implements ModuleFinder {
*/
static {
long t0 = System.nanoTime();
- imageReader = ImageReaderFactory.getImageReader();
INSTANCE = new SystemModuleFinder();
initTime.addElapsedTimeFrom(t0);
}
+ /**
+ * Holder class for the ImageReader
+ */
+ private static class SystemImage {
+ static final ImageReader READER;
+ static {
+ long t0 = System.nanoTime();
+ READER = ImageReaderFactory.getImageReader();
+ initTime.addElapsedTimeFrom(t0);
+ }
+
+ static ImageReader reader() {
+ return READER;
+ }
+ }
+
private static boolean isFastPathSupported() {
return SystemModules.MODULE_NAMES.length > 0;
}
@@ -114,7 +127,7 @@ public class SystemModuleFinder implements ModuleFinder {
// this happens when java.base is patched with java.base
// from an exploded image
- return imageReader.getModuleNames();
+ return SystemImage.reader().getModuleNames();
}
// the set of modules in the run-time image
@@ -151,6 +164,7 @@ public class SystemModuleFinder implements ModuleFinder {
descriptors = new ModuleDescriptor[n];
recordedHashes = new ModuleHashes[n];
moduleResolutions = new ModuleResolution[n];
+ ImageReader imageReader = SystemImage.reader();
for (int i = 0; i < names.length; i++) {
String mn = names[i];
ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
@@ -291,6 +305,7 @@ public class SystemModuleFinder implements ModuleFinder {
Objects.requireNonNull(name);
if (closed)
throw new IOException("ModuleReader is closed");
+ ImageReader imageReader = SystemImage.reader();
if (imageReader != null) {
return imageReader.findLocation(module, name);
} else {
@@ -330,7 +345,7 @@ public class SystemModuleFinder implements ModuleFinder {
public Optional read(String name) throws IOException {
ImageLocation location = findImageLocation(name);
if (location != null) {
- return Optional.of(imageReader.getResourceBuffer(location));
+ return Optional.of(SystemImage.reader().getResourceBuffer(location));
} else {
return Optional.empty();
}
@@ -372,7 +387,7 @@ public class SystemModuleFinder implements ModuleFinder {
stack = new ArrayDeque<>();
// push the root node to the stack to get started
- ImageReader.Node dir = imageReader.findNode(moduleRoot);
+ ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
if (dir == null || !dir.isDirectory())
throw new IOException(moduleRoot + " not a directory");
stack.push(dir);
@@ -390,7 +405,7 @@ public class SystemModuleFinder implements ModuleFinder {
String name = node.getName();
if (node.isDirectory()) {
// build node
- ImageReader.Node dir = imageReader.findNode(name);
+ ImageReader.Node dir = SystemImage.reader().findNode(name);
assert dir.isDirectory();
stack.push(dir);
} else {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
index 9a410049188..61969590d92 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -211,15 +211,7 @@ public class Reflection {
if (currentModule == memberModule)
return true; // same module (named or unnamed)
- // memberClass may be primitive or array class
- Class> c = memberClass;
- while (c.isArray()) {
- c = c.getComponentType();
- }
- if (c.isPrimitive())
- return true;
-
- String pkg = c.getPackageName();
+ String pkg = memberClass.getPackageName();
boolean allowed = memberModule.isExported(pkg, currentModule);
if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) {
if (!SharedSecrets.getJavaLangReflectModuleAccess()
@@ -237,10 +229,6 @@ public class Reflection {
private static boolean isSameClassPackage(Class> c1, Class> c2) {
if (c1.getClassLoader() != c2.getClassLoader())
return false;
- while (c1.isArray())
- c1 = c1.getComponentType();
- while (c2.isArray())
- c2 = c2.getComponentType();
return Objects.equals(c1.getPackageName(), c2.getPackageName());
}
@@ -378,12 +366,6 @@ public class Reflection {
}
}
- public static void enableStackTraces() {
- printStackWhenAccessFails = true;
- printStackWhenAccessSucceeds = true;
- printStackPropertiesSet = true;
- }
-
public static boolean printStackTraceWhenAccessFails() {
ensurePrintStackPropertiesSet();
return printStackWhenAccessFails;
@@ -413,11 +395,7 @@ public class Reflection {
if (m2.isNamed())
memberSuffix = " (in " + m2 + ")";
- Class> c = memberClass;
- while (c.isArray()) {
- c = c.getComponentType();
- }
- String memberPackageName = c.getPackageName();
+ String memberPackageName = memberClass.getPackageName();
String msg = currentClass + currentSuffix + " cannot access ";
if (m2.isExported(memberPackageName, m1)) {
diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java
index 185f8f2a1d1..3ad3f4a096c 100644
--- a/jdk/src/java.base/share/classes/module-info.java
+++ b/jdk/src/java.base/share/classes/module-info.java
@@ -25,6 +25,8 @@
/**
* Defines the foundational APIs of the Java SE Platform.
+ *
+ * @since 9
*/
module java.base {
diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java
index 9c46aad018f..c3633ff8aab 100644
--- a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java
+++ b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@ public class VerifyAccess {
private VerifyAccess() { } // cannot instantiate
+ private static final int UNCONDITIONAL_ALLOWED = java.lang.invoke.MethodHandles.Lookup.UNCONDITIONAL;
private static final int MODULE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.MODULE;
private static final int PACKAGE_ONLY = 0;
private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE;
@@ -92,7 +93,7 @@ public class VerifyAccess {
int allowedModes) {
if (allowedModes == 0) return false;
assert((allowedModes & PUBLIC) != 0 &&
- (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0);
+ (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
// The symbolic reference class (refc) must always be fully verified.
if (!isClassAccessible(refc, lookupClass, allowedModes)) {
return false;
@@ -173,7 +174,7 @@ public class VerifyAccess {
int allowedModes) {
if (allowedModes == 0) return false;
assert((allowedModes & PUBLIC) != 0 &&
- (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0);
+ (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
int mods = getClassModifiers(refc);
if (isPublic(mods)) {
@@ -191,22 +192,17 @@ public class VerifyAccess {
(lookupModule == refModule))
return true;
- // check readability
- if (lookupModule.canRead(refModule)) {
+ // check readability when UNCONDITIONAL not allowed
+ if (((allowedModes & UNCONDITIONAL_ALLOWED) != 0)
+ || lookupModule.canRead(refModule)) {
// check that refc is in an exported package
- Class> c = refc;
- while (c.isArray()) {
- c = c.getComponentType();
- }
- if (c.isPrimitive())
- return true;
if ((allowedModes & MODULE_ALLOWED) != 0) {
- if (refModule.isExported(c.getPackageName(), lookupModule))
+ if (refModule.isExported(refc.getPackageName(), lookupModule))
return true;
} else {
// exported unconditionally
- if (refModule.isExported(c.getPackageName()))
+ if (refModule.isExported(refc.getPackageName()))
return true;
}
diff --git a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
index ee8f311d2e4..39df984054b 100644
--- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
+++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
@@ -591,8 +591,8 @@ public final class LauncherHelper {
c = Class.forName(m, cn);
}
} catch (LinkageError le) {
- abort(null, "java.launcher.module.error3",
- mainClass, m.getName(), le.getLocalizedMessage());
+ abort(null, "java.launcher.module.error3", mainClass, m.getName(),
+ le.getClass().getName() + ": " + le.getLocalizedMessage());
}
if (c == null) {
abort(null, "java.launcher.module.error2", mainClass, mainModule);
@@ -645,7 +645,8 @@ public final class LauncherHelper {
}
}
} catch (LinkageError le) {
- abort(le, "java.launcher.cls.error6", cn, le.getLocalizedMessage());
+ abort(le, "java.launcher.cls.error6", cn,
+ le.getClass().getName() + ": " + le.getLocalizedMessage());
}
return mainClass;
}
@@ -966,6 +967,10 @@ public final class LauncherHelper {
ostream.print("open ");
if (md.isAutomatic())
ostream.print("automatic ");
+ if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC))
+ ostream.print("synthetic ");
+ if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED))
+ ostream.print("mandated ");
ostream.println("module " + midAndLocation(md, mref.location()));
// unqualified exports (sorted by package)
diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java
index 88e6f5b7caa..893bb55c10a 100644
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java
@@ -32,7 +32,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.security.AccessController;
import java.security.Permission;
+import java.security.PrivilegedAction;
import jdk.internal.jimage.ImageLocation;
import jdk.internal.jimage.ImageReader;
@@ -51,7 +53,11 @@ import sun.security.action.GetPropertyAction;
public class JavaRuntimeURLConnection extends URLConnection {
// ImageReader to access resources in jimage
- private static final ImageReader reader = ImageReaderFactory.getImageReader();
+ private static final ImageReader reader;
+ static {
+ PrivilegedAction pa = ImageReaderFactory::getImageReader;
+ reader = AccessController.doPrivileged(pa);
+ }
// the module and resource name in the URL
private final String module;
diff --git a/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
index ed69ba3d8b9..6efd90d0670 100644
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.Timestamp;
+import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertPath;
@@ -48,6 +49,7 @@ import java.util.EnumSet;
import java.util.Set;
import sun.security.timestamp.TimestampToken;
+import sun.security.util.ConstraintsParameters;
import sun.security.util.Debug;
import sun.security.util.DerEncoder;
import sun.security.util.DerInputStream;
@@ -321,6 +323,8 @@ public class SignerInfo implements DerEncoder {
data = content.getContentBytes();
}
+ ConstraintsParameters cparams =
+ new ConstraintsParameters(timestamp);
String digestAlgname = getDigestAlgorithmId().getName();
byte[] dataSigned;
@@ -347,11 +351,11 @@ public class SignerInfo implements DerEncoder {
if (messageDigest == null) // fail if there is no message digest
return null;
- // check that algorithm is not restricted
- if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET,
- digestAlgname, null)) {
- throw new SignatureException("Digest check failed. " +
- "Disabled algorithm used: " + digestAlgname);
+ // check that digest algorithm is not restricted
+ try {
+ JAR_DISABLED_CHECK.permits(digestAlgname, cparams);
+ } catch (CertPathValidatorException e) {
+ throw new SignatureException(e.getMessage(), e);
}
MessageDigest md = MessageDigest.getInstance(digestAlgname);
@@ -385,17 +389,18 @@ public class SignerInfo implements DerEncoder {
String algname = AlgorithmId.makeSigAlg(
digestAlgname, encryptionAlgname);
- // check that algorithm is not restricted
- if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) {
- throw new SignatureException("Signature check failed. " +
- "Disabled algorithm used: " + algname);
+ // check that jar signature algorithm is not restricted
+ try {
+ JAR_DISABLED_CHECK.permits(algname, cparams);
+ } catch (CertPathValidatorException e) {
+ throw new SignatureException(e.getMessage(), e);
}
X509Certificate cert = getCertificate(block);
- PublicKey key = cert.getPublicKey();
if (cert == null) {
return null;
}
+ PublicKey key = cert.getPublicKey();
// check if the public key is restricted
if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
index 90559598aee..a12484d0e20 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
* 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 @@ package sun.security.provider.certpath;
import java.security.AlgorithmConstraints;
import java.security.CryptoPrimitive;
import java.security.Timestamp;
+import java.security.cert.CertPathValidator;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -53,9 +54,10 @@ import java.security.interfaces.DSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import sun.security.util.AnchorCertificates;
-import sun.security.util.CertConstraintParameters;
+import sun.security.util.ConstraintsParameters;
import sun.security.util.Debug;
import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.validator.Validator;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CRLImpl;
import sun.security.x509.AlgorithmId;
@@ -79,6 +81,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
private final Date pkixdate;
private PublicKey prevPubKey;
private final Timestamp jarTimestamp;
+ private final String variant;
private static final Set SIGNATURE_PRIMITIVE_SET =
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
@@ -109,64 +112,36 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
*
* @param anchor the trust anchor selected to validate the target
* certificate
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
- public AlgorithmChecker(TrustAnchor anchor) {
- this(anchor, certPathDefaultConstraints, null);
- }
-
- /**
- * Create a new {@code AlgorithmChecker} with the
- * given {@code TrustAnchor} and {@code AlgorithmConstraints}.
- *
- * @param anchor the trust anchor selected to validate the target
- * certificate
- * @param constraints the algorithm constraints (or null)
- *
- * @throws IllegalArgumentException if the {@code anchor} is null
- */
- public AlgorithmChecker(TrustAnchor anchor,
- AlgorithmConstraints constraints) {
- this(anchor, constraints, null);
- }
-
- /**
- * Create a new {@code AlgorithmChecker} with the
- * given {@code AlgorithmConstraints}.
- *
- * Note that this constructor will be used to check a certification
- * path where the trust anchor is unknown, or a certificate list which may
- * contain the trust anchor. This constructor is used by SunJSSE.
- *
- * @param constraints the algorithm constraints (or null)
- */
- public AlgorithmChecker(AlgorithmConstraints constraints) {
- this.prevPubKey = null;
- this.trustedPubKey = null;
- this.constraints = constraints;
- this.pkixdate = null;
- this.jarTimestamp = null;
+ public AlgorithmChecker(TrustAnchor anchor, String variant) {
+ this(anchor, certPathDefaultConstraints, null, variant);
}
/**
* Create a new {@code AlgorithmChecker} with the given
- * {@code Timestamp}.
+ * {@code AlgorithmConstraints}, {@code Timestamp}, and/or {@code Variant}.
*
- * Note that this constructor will be used to check a certification
- * path for signed JAR files that are timestamped.
+ * Note that this constructor can initialize a variation of situations where
+ * the AlgorithmConstraints, Timestamp, or Variant maybe known.
*
+ * @param constraints the algorithm constraints (or null)
* @param jarTimestamp Timestamp passed for JAR timestamp constraint
* checking. Set to null if not applicable.
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
- public AlgorithmChecker(Timestamp jarTimestamp) {
+ public AlgorithmChecker(AlgorithmConstraints constraints,
+ Timestamp jarTimestamp, String variant) {
this.prevPubKey = null;
this.trustedPubKey = null;
- this.constraints = certPathDefaultConstraints;
- if (jarTimestamp == null) {
- throw new IllegalArgumentException(
- "Timestamp cannot be null");
- }
- this.pkixdate = jarTimestamp.getTimestamp();
+ this.constraints = (constraints == null ? certPathDefaultConstraints :
+ constraints);
+ this.pkixdate = (jarTimestamp != null ? jarTimestamp.getTimestamp() :
+ null);
this.jarTimestamp = jarTimestamp;
+ this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
}
/**
@@ -178,12 +153,13 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
* @param constraints the algorithm constraints (or null)
* @param pkixdate Date the constraints are checked against. The value is
* either the PKIXParameter date or null for the current date.
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*
* @throws IllegalArgumentException if the {@code anchor} is null
*/
public AlgorithmChecker(TrustAnchor anchor,
- AlgorithmConstraints constraints,
- Date pkixdate) {
+ AlgorithmConstraints constraints, Date pkixdate, String variant) {
if (anchor != null) {
if (anchor.getTrustedCert() != null) {
@@ -207,6 +183,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
this.constraints = constraints;
this.pkixdate = pkixdate;
this.jarTimestamp = null;
+ this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
}
/**
@@ -217,11 +194,13 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
* certificate
* @param pkixdate Date the constraints are checked against. The value is
* either the PKIXParameter date or null for the current date.
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*
* @throws IllegalArgumentException if the {@code anchor} is null
*/
- public AlgorithmChecker(TrustAnchor anchor, Date pkixdate) {
- this(anchor, certPathDefaultConstraints, pkixdate);
+ public AlgorithmChecker(TrustAnchor anchor, Date pkixdate, String variant) {
+ this(anchor, certPathDefaultConstraints, pkixdate, variant);
}
// Check this 'cert' for restrictions in the AnchorCertificates
@@ -286,6 +265,28 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
null, null, -1, PKIXReason.INVALID_KEY_USAGE);
}
+ X509CertImpl x509Cert;
+ AlgorithmId algorithmId;
+ try {
+ x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
+ algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
+ } catch (CertificateException ce) {
+ throw new CertPathValidatorException(ce);
+ }
+
+ AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
+ PublicKey currPubKey = cert.getPublicKey();
+ String currSigAlg = x509Cert.getSigAlgName();
+
+ // Check the signature algorithm and parameters against constraints.
+ if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, currSigAlg,
+ currSigAlgParams)) {
+ throw new CertPathValidatorException(
+ "Algorithm constraints check failed on signature " +
+ "algorithm: " + currSigAlg, null, null, -1,
+ BasicReason.ALGORITHM_CONSTRAINED);
+ }
+
// Assume all key usage bits are set if key usage is not present
Set primitives = KU_PRIMITIVE_SET;
@@ -322,101 +323,74 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
}
}
- PublicKey currPubKey = cert.getPublicKey();
+ ConstraintsParameters cp =
+ new ConstraintsParameters((X509Certificate)cert,
+ trustedMatch, pkixdate, jarTimestamp, variant);
+ // Check against local constraints if it is DisabledAlgorithmConstraints
if (constraints instanceof DisabledAlgorithmConstraints) {
- // Check against DisabledAlgorithmConstraints certpath constraints.
- // permits() will throw exception on failure.
- ((DisabledAlgorithmConstraints)constraints).permits(primitives,
- new CertConstraintParameters((X509Certificate)cert,
- trustedMatch, pkixdate, jarTimestamp));
- // If there is no previous key, set one and exit
- if (prevPubKey == null) {
- prevPubKey = currPubKey;
- return;
- }
- }
-
- X509CertImpl x509Cert;
- AlgorithmId algorithmId;
- try {
- x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
- algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
- } catch (CertificateException ce) {
- throw new CertPathValidatorException(ce);
- }
-
- AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
- String currSigAlg = x509Cert.getSigAlgName();
-
- // If 'constraints' is not of DisabledAlgorithmConstraints, check all
- // everything individually
- if (!(constraints instanceof DisabledAlgorithmConstraints)) {
- // Check the current signature algorithm
- if (!constraints.permits(
- SIGNATURE_PRIMITIVE_SET,
- currSigAlg, currSigAlgParams)) {
- throw new CertPathValidatorException(
- "Algorithm constraints check failed on signature " +
- "algorithm: " + currSigAlg, null, null, -1,
- BasicReason.ALGORITHM_CONSTRAINED);
- }
+ ((DisabledAlgorithmConstraints)constraints).permits(currSigAlg, cp);
+ // DisabledAlgorithmsConstraints does not check primitives, so key
+ // additional key check.
+ } else {
+ // Perform the default constraints checking anyway.
+ certPathDefaultConstraints.permits(currSigAlg, cp);
+ // Call locally set constraints to check key with primitives.
if (!constraints.permits(primitives, currPubKey)) {
throw new CertPathValidatorException(
- "Algorithm constraints check failed on keysize: " +
- sun.security.util.KeyUtil.getKeySize(currPubKey),
+ "Algorithm constraints check failed on key " +
+ currPubKey.getAlgorithm() + " with size of " +
+ sun.security.util.KeyUtil.getKeySize(currPubKey) +
+ "bits",
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
}
+ // If there is no previous key, set one and exit
+ if (prevPubKey == null) {
+ prevPubKey = currPubKey;
+ return;
+ }
+
// Check with previous cert for signature algorithm and public key
- if (prevPubKey != null) {
- if (!constraints.permits(
- SIGNATURE_PRIMITIVE_SET,
- currSigAlg, prevPubKey, currSigAlgParams)) {
- throw new CertPathValidatorException(
+ if (!constraints.permits(
+ SIGNATURE_PRIMITIVE_SET,
+ currSigAlg, prevPubKey, currSigAlgParams)) {
+ throw new CertPathValidatorException(
"Algorithm constraints check failed on " +
"signature algorithm: " + currSigAlg,
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+ }
+
+ // Inherit key parameters from previous key
+ if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) {
+ // Inherit DSA parameters from previous key
+ if (!(prevPubKey instanceof DSAPublicKey)) {
+ throw new CertPathValidatorException("Input key is not " +
+ "of a appropriate type for inheriting parameters");
}
- // Inherit key parameters from previous key
- if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) {
- // Inherit DSA parameters from previous key
- if (!(prevPubKey instanceof DSAPublicKey)) {
- throw new CertPathValidatorException("Input key is not " +
- "of a appropriate type for inheriting parameters");
- }
-
- DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
- if (params == null) {
- throw new CertPathValidatorException(
+ DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
+ if (params == null) {
+ throw new CertPathValidatorException(
"Key parameters missing from public key.");
- }
+ }
- try {
- BigInteger y = ((DSAPublicKey)currPubKey).getY();
- KeyFactory kf = KeyFactory.getInstance("DSA");
- DSAPublicKeySpec ks = new DSAPublicKeySpec(y,
- params.getP(),
- params.getQ(),
- params.getG());
- currPubKey = kf.generatePublic(ks);
- } catch (GeneralSecurityException e) {
- throw new CertPathValidatorException("Unable to generate " +
+ try {
+ BigInteger y = ((DSAPublicKey)currPubKey).getY();
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPublicKeySpec ks = new DSAPublicKeySpec(y, params.getP(),
+ params.getQ(), params.getG());
+ currPubKey = kf.generatePublic(ks);
+ } catch (GeneralSecurityException e) {
+ throw new CertPathValidatorException("Unable to generate " +
"key with inherited parameters: " + e.getMessage(), e);
- }
}
}
// reset the previous public key
prevPubKey = currPubKey;
-
- // check the extended key usage, ignore the check now
- // List extendedKeyUsages = x509Cert.getExtendedKeyUsage();
-
- // DO NOT remove any unresolved critical extensions
}
/**
@@ -456,8 +430,10 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
*
* @param key the public key to verify the CRL signature
* @param crl the target CRL
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
- static void check(PublicKey key, X509CRL crl)
+ static void check(PublicKey key, X509CRL crl, String variant)
throws CertPathValidatorException {
X509CRLImpl x509CRLImpl = null;
@@ -468,7 +444,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
}
AlgorithmId algorithmId = x509CRLImpl.getSigAlgId();
- check(key, algorithmId);
+ check(key, algorithmId, variant);
}
/**
@@ -476,20 +452,16 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
*
* @param key the public key to verify the CRL signature
* @param algorithmId signature algorithm Algorithm ID
+ * @param variant is the Validator variants of the operation. A null value
+ * passed will set it to Validator.GENERIC.
*/
- static void check(PublicKey key, AlgorithmId algorithmId)
+ static void check(PublicKey key, AlgorithmId algorithmId, String variant)
throws CertPathValidatorException {
String sigAlgName = algorithmId.getName();
AlgorithmParameters sigAlgParams = algorithmId.getParameters();
- if (!certPathDefaultConstraints.permits(
- SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
- throw new CertPathValidatorException(
- "Algorithm constraints check failed on signature algorithm: " +
- sigAlgName + " is disabled",
- null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
- }
+ certPathDefaultConstraints.permits(new ConstraintsParameters(
+ sigAlgName, sigAlgParams, key, variant));
}
-
}
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
index 95ef350a9d3..0f16c646a9c 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@ import javax.security.auth.x500.X500Principal;
import java.util.*;
import sun.security.util.Debug;
+import sun.security.validator.Validator;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.x509.*;
@@ -65,6 +66,20 @@ public class DistributionPointFetcher {
* Return the X509CRLs matching this selector. The selector must be
* an X509CRLSelector with certificateChecking set.
*/
+ public static Collection getCRLs(X509CRLSelector selector,
+ boolean signFlag, PublicKey prevKey, String provider,
+ List certStores, boolean[] reasonsMask,
+ Set trustAnchors, Date validity, String variant)
+ throws CertStoreException
+ {
+ return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
+ reasonsMask, trustAnchors, validity, variant);
+ }
+ /**
+ * Return the X509CRLs matching this selector. The selector must be
+ * an X509CRLSelector with certificateChecking set.
+ */
+ // Called by com.sun.deploy.security.RevocationChecker
public static Collection getCRLs(X509CRLSelector selector,
boolean signFlag,
PublicKey prevKey,
@@ -76,7 +91,7 @@ public class DistributionPointFetcher {
throws CertStoreException
{
return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
- reasonsMask, trustAnchors, validity);
+ reasonsMask, trustAnchors, validity, Validator.VAR_GENERIC);
}
/**
@@ -91,7 +106,8 @@ public class DistributionPointFetcher {
List certStores,
boolean[] reasonsMask,
Set trustAnchors,
- Date validity)
+ Date validity,
+ String variant)
throws CertStoreException
{
X509Certificate cert = selector.getCertificateChecking();
@@ -120,7 +136,7 @@ public class DistributionPointFetcher {
DistributionPoint point = t.next();
Collection crls = getCRLs(selector, certImpl,
point, reasonsMask, signFlag, prevKey, prevCert, provider,
- certStores, trustAnchors, validity);
+ certStores, trustAnchors, validity, variant);
results.addAll(crls);
}
if (debug != null) {
@@ -145,7 +161,7 @@ public class DistributionPointFetcher {
X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask,
boolean signFlag, PublicKey prevKey, X509Certificate prevCert,
String provider, List certStores,
- Set trustAnchors, Date validity)
+ Set trustAnchors, Date validity, String variant)
throws CertStoreException {
// check for full name
@@ -208,7 +224,7 @@ public class DistributionPointFetcher {
selector.setIssuerNames(null);
if (selector.match(crl) && verifyCRL(certImpl, point, crl,
reasonsMask, signFlag, prevKey, prevCert, provider,
- trustAnchors, certStores, validity)) {
+ trustAnchors, certStores, validity, variant)) {
crls.add(crl);
}
} catch (IOException | CRLException e) {
@@ -316,7 +332,7 @@ public class DistributionPointFetcher {
X509CRL crl, boolean[] reasonsMask, boolean signFlag,
PublicKey prevKey, X509Certificate prevCert, String provider,
Set trustAnchors, List certStores,
- Date validity) throws CRLException, IOException {
+ Date validity, String variant) throws CRLException, IOException {
if (debug != null) {
debug.println("DistributionPointFetcher.verifyCRL: " +
@@ -663,7 +679,7 @@ public class DistributionPointFetcher {
// check the crl signature algorithm
try {
- AlgorithmChecker.check(prevKey, crl);
+ AlgorithmChecker.check(prevKey, crl, variant);
} catch (CertPathValidatorException cpve) {
if (debug != null) {
debug.println("CRL signature algorithm check failed: " + cpve);
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java
index 8753072e9d0..dce73028cd0 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,7 @@ import java.util.Map;
import sun.security.action.GetIntegerAction;
import sun.security.util.Debug;
+import sun.security.validator.Validator;
import sun.security.x509.AccessDescription;
import sun.security.x509.AuthorityInfoAccessExtension;
import sun.security.x509.GeneralName;
@@ -94,42 +95,6 @@ public final class OCSP {
private OCSP() {}
- /**
- * Obtains the revocation status of a certificate using OCSP using the most
- * common defaults. The OCSP responder URI is retrieved from the
- * certificate's AIA extension. The OCSP responder certificate is assumed
- * to be the issuer's certificate (or issued by the issuer CA).
- *
- * @param cert the certificate to be checked
- * @param issuerCert the issuer certificate
- * @return the RevocationStatus
- * @throws IOException if there is an exception connecting to or
- * communicating with the OCSP responder
- * @throws CertPathValidatorException if an exception occurs while
- * encoding the OCSP Request or validating the OCSP Response
- */
- public static RevocationStatus check(X509Certificate cert,
- X509Certificate issuerCert)
- throws IOException, CertPathValidatorException {
- CertId certId = null;
- URI responderURI = null;
- try {
- X509CertImpl certImpl = X509CertImpl.toImpl(cert);
- responderURI = getResponderURI(certImpl);
- if (responderURI == null) {
- throw new CertPathValidatorException
- ("No OCSP Responder URI in certificate");
- }
- certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
- } catch (CertificateException | IOException e) {
- throw new CertPathValidatorException
- ("Exception while encoding OCSPRequest", e);
- }
- OCSPResponse ocspResponse = check(Collections.singletonList(certId),
- responderURI, new OCSPResponse.IssuerInfo(issuerCert), null, null,
- Collections.emptyList());
- return (RevocationStatus)ocspResponse.getSingleResponse(certId);
- }
/**
* Obtains the revocation status of a certificate using OCSP.
@@ -146,6 +111,8 @@ public final class OCSP {
* @throws CertPathValidatorException if an exception occurs while
* encoding the OCSP Request or validating the OCSP Response
*/
+
+ // Called by com.sun.deploy.security.TrustDecider
public static RevocationStatus check(X509Certificate cert,
X509Certificate issuerCert,
URI responderURI,
@@ -154,27 +121,27 @@ public final class OCSP {
throws IOException, CertPathValidatorException
{
return check(cert, issuerCert, responderURI, responderCert, date,
- Collections.emptyList());
+ Collections.emptyList(), Validator.VAR_GENERIC);
}
- // Called by com.sun.deploy.security.TrustDecider
+
public static RevocationStatus check(X509Certificate cert,
- X509Certificate issuerCert,
- URI responderURI,
- X509Certificate responderCert,
- Date date, List extensions)
+ X509Certificate issuerCert, URI responderURI,
+ X509Certificate responderCert, Date date, List extensions,
+ String variant)
throws IOException, CertPathValidatorException
{
- return check(cert, responderURI, null, issuerCert, responderCert, date, extensions);
+ return check(cert, responderURI, null, issuerCert, responderCert, date,
+ extensions, variant);
}
public static RevocationStatus check(X509Certificate cert,
URI responderURI, TrustAnchor anchor, X509Certificate issuerCert,
X509Certificate responderCert, Date date,
- List extensions)
+ List extensions, String variant)
throws IOException, CertPathValidatorException
{
- CertId certId = null;
+ CertId certId;
try {
X509CertImpl certImpl = X509CertImpl.toImpl(cert);
certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
@@ -184,7 +151,7 @@ public final class OCSP {
}
OCSPResponse ocspResponse = check(Collections.singletonList(certId),
responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert),
- responderCert, date, extensions);
+ responderCert, date, extensions, variant);
return (RevocationStatus) ocspResponse.getSingleResponse(certId);
}
@@ -206,10 +173,10 @@ public final class OCSP {
* @throws CertPathValidatorException if an exception occurs while
* encoding the OCSP Request or validating the OCSP Response
*/
- static OCSPResponse check(List certIds, URI responderURI,
+ static OCSPResponse check(List certIds, URI responderURI,
OCSPResponse.IssuerInfo issuerInfo,
X509Certificate responderCert, Date date,
- List extensions)
+ List extensions, String variant)
throws IOException, CertPathValidatorException
{
byte[] nonce = null;
@@ -226,7 +193,7 @@ public final class OCSP {
// verify the response
ocspResponse.verify(certIds, issuerInfo, responderCert, date,
- nonce);
+ nonce, variant);
} catch (IOException ioe) {
throw new CertPathValidatorException(
"Unable to determine revocation status due to network error",
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java
index d1770da153a..11f1b0996db 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,6 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
@@ -375,7 +374,8 @@ public final class OCSPResponse {
}
void verify(List certIds, IssuerInfo issuerInfo,
- X509Certificate responderCert, Date date, byte[] nonce)
+ X509Certificate responderCert, Date date, byte[] nonce,
+ String variant)
throws CertPathValidatorException
{
switch (responseStatus) {
@@ -508,7 +508,8 @@ public final class OCSPResponse {
// Check algorithm constraints specified in security property
// "jdk.certpath.disabledAlgorithms".
AlgorithmChecker algChecker =
- new AlgorithmChecker(issuerInfo.getAnchor(), date);
+ new AlgorithmChecker(issuerInfo.getAnchor(), date,
+ variant);
algChecker.init(false);
algChecker.check(signerCert, Collections.emptySet());
@@ -568,7 +569,7 @@ public final class OCSPResponse {
if (signerCert != null) {
// Check algorithm constraints specified in security property
// "jdk.certpath.disabledAlgorithms".
- AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId);
+ AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId, variant);
if (!verifySignature(signerCert)) {
throw new CertPathValidatorException(
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java
index f6b0b2ed6f3..8a177c04fc1 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -87,6 +87,7 @@ class PKIX {
private Set anchors;
private List certs;
private Timestamp timestamp;
+ private String variant;
ValidatorParams(CertPath cp, PKIXParameters params)
throws InvalidAlgorithmParameterException
@@ -102,8 +103,9 @@ class PKIX {
ValidatorParams(PKIXParameters params)
throws InvalidAlgorithmParameterException
{
- if (params instanceof PKIXTimestampParameters) {
- timestamp = ((PKIXTimestampParameters) params).getTimestamp();
+ if (params instanceof PKIXExtendedParameters) {
+ timestamp = ((PKIXExtendedParameters) params).getTimestamp();
+ variant = ((PKIXExtendedParameters) params).getVariant();
}
this.anchors = params.getTrustAnchors();
@@ -199,6 +201,10 @@ class PKIX {
Timestamp timestamp() {
return timestamp;
}
+
+ String variant() {
+ return variant;
+ }
}
static class BuilderParams extends ValidatorParams {
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java
index ac12fab75ab..b8e20e832f1 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -173,9 +173,10 @@ public final class PKIXCertPathValidator extends CertPathValidatorSpi {
// add standard checkers that we will be using
certPathCheckers.add(untrustedChecker);
if (params.timestamp() == null) {
- certPathCheckers.add(new AlgorithmChecker(anchor, params.date()));
+ certPathCheckers.add(new AlgorithmChecker(anchor, params.date(), null));
} else {
- certPathCheckers.add(new AlgorithmChecker(params.timestamp()));
+ certPathCheckers.add(new AlgorithmChecker(null,
+ params.timestamp(), params.variant()));
}
certPathCheckers.add(new KeyChecker(certPathLen,
params.targetCertConstraints()));
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXTimestampParameters.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java
similarity index 91%
rename from jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXTimestampParameters.java
rename to jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java
index 34b497188e0..42c2d1f9c4f 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXTimestampParameters.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,19 +39,23 @@ import java.util.Set;
/**
* This class is a wrapper for PKIXBuilderParameters so that a Timestamp object
- * can be passed alone when PKIXCertPath is checking signed jar files.
+ * and a string for the variant type, can be passed when doing certpath
+ * checking.
*/
-public class PKIXTimestampParameters extends PKIXBuilderParameters {
+public class PKIXExtendedParameters extends PKIXBuilderParameters {
private final PKIXBuilderParameters p;
private Timestamp jarTimestamp;
+ private final String variant;
- public PKIXTimestampParameters(PKIXBuilderParameters params,
- Timestamp timestamp) throws InvalidAlgorithmParameterException {
+ public PKIXExtendedParameters(PKIXBuilderParameters params,
+ Timestamp timestamp, String variant)
+ throws InvalidAlgorithmParameterException {
super(params.getTrustAnchors(), null);
p = params;
jarTimestamp = timestamp;
+ this.variant = variant;
}
public Timestamp getTimestamp() {
@@ -61,6 +65,10 @@ public class PKIXTimestampParameters extends PKIXBuilderParameters {
jarTimestamp = t;
}
+ public String getVariant() {
+ return variant;
+ }
+
@Override
public void setDate(Date d) {
p.setDate(d);
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java
index 5fba1666119..9b443a733dd 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -579,7 +579,7 @@ class RevocationChecker extends PKIXRevocationChecker {
approvedCRLs.addAll(DistributionPointFetcher.getCRLs(
sel, signFlag, prevKey, prevCert,
params.sigProvider(), certStores,
- reasonsMask, anchors, null));
+ reasonsMask, anchors, null, params.variant()));
}
} catch (CertStoreException e) {
if (e instanceof CertStoreTypeException) {
@@ -727,7 +727,7 @@ class RevocationChecker extends PKIXRevocationChecker {
}
}
response.verify(Collections.singletonList(certId), issuerInfo,
- responderCert, params.date(), nonce);
+ responderCert, params.date(), nonce, params.variant());
} else {
URI responderURI = (this.responderURI != null)
@@ -741,7 +741,7 @@ class RevocationChecker extends PKIXRevocationChecker {
response = OCSP.check(Collections.singletonList(certId),
responderURI, issuerInfo, responderCert, null,
- ocspExtensions);
+ ocspExtensions, params.variant());
}
} catch (IOException e) {
throw new CertPathValidatorException(
@@ -853,7 +853,7 @@ class RevocationChecker extends PKIXRevocationChecker {
if (DistributionPointFetcher.verifyCRL(
certImpl, point, crl, reasonsMask, signFlag,
prevKey, null, params.sigProvider(), anchors,
- certStores, params.date()))
+ certStores, params.date(), params.variant()))
{
results.add(crl);
}
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
index c0cc98a7a36..11d8a067329 100644
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -344,7 +344,7 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
// add the algorithm checker
checkers.add(new AlgorithmChecker(builder.trustAnchor,
- buildParams.date()));
+ buildParams.date(), null));
BasicChecker basicChecker = null;
if (nextState.keyParamsNeeded()) {
diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java b/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java
index d4f2848c973..c91b25e72ef 100644
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,9 @@ import sun.security.action.GetPropertyAction;
final class EllipticCurvesExtension extends HelloExtension {
+ /* Class and subclass dynamic debugging support */
+ private static final Debug debug = Debug.getInstance("ssl");
+
private static final int ARBITRARY_PRIME = 0xff01;
private static final int ARBITRARY_CHAR2 = 0xff02;
@@ -159,6 +162,11 @@ final class EllipticCurvesExtension extends HelloExtension {
} // ignore unknown curves
}
}
+ if (idList.isEmpty() && JsseJce.isEcAvailable()) {
+ throw new IllegalArgumentException(
+ "System property jdk.tls.namedGroups(" + property + ") " +
+ "contains no supported elliptic curves");
+ }
} else { // default curves
int[] ids;
if (requireFips) {
@@ -183,16 +191,17 @@ final class EllipticCurvesExtension extends HelloExtension {
}
}
- if (idList.isEmpty()) {
- throw new IllegalArgumentException(
- "System property jdk.tls.namedGroups(" + property + ") " +
- "contains no supported elliptic curves");
- } else {
- supportedCurveIds = new int[idList.size()];
- int i = 0;
- for (Integer id : idList) {
- supportedCurveIds[i++] = id;
- }
+ if (debug != null && idList.isEmpty()) {
+ Debug.log(
+ "Initialized [jdk.tls.namedGroups|default] list contains " +
+ "no available elliptic curves. " +
+ (property != null ? "(" + property + ")" : "[Default]"));
+ }
+
+ supportedCurveIds = new int[idList.size()];
+ int i = 0;
+ for (Integer id : idList) {
+ supportedCurveIds[i++] = id;
}
}
diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
index 46ae8d5281e..4f0a95ff80b 100644
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@ import javax.net.ssl.*;
import sun.security.provider.certpath.AlgorithmChecker;
import sun.security.action.GetPropertyAction;
+import sun.security.validator.Validator;
public abstract class SSLContextImpl extends SSLContextSpi {
@@ -1436,7 +1437,7 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
constraints = new SSLAlgorithmConstraints(sslSocket, true);
}
- checkAlgorithmConstraints(chain, constraints);
+ checkAlgorithmConstraints(chain, constraints, isClient);
}
}
@@ -1478,12 +1479,12 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
constraints = new SSLAlgorithmConstraints(engine, true);
}
- checkAlgorithmConstraints(chain, constraints);
+ checkAlgorithmConstraints(chain, constraints, isClient);
}
}
private void checkAlgorithmConstraints(X509Certificate[] chain,
- AlgorithmConstraints constraints) throws CertificateException {
+ AlgorithmConstraints constraints, boolean isClient) throws CertificateException {
try {
// Does the certificate chain end with a trusted certificate?
@@ -1501,7 +1502,9 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
// A forward checker, need to check from trust to target
if (checkedLength >= 0) {
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
+ AlgorithmChecker checker =
+ new AlgorithmChecker(constraints, null,
+ (isClient ? Validator.VAR_TLS_CLIENT : Validator.VAR_TLS_SERVER));
checker.init(false);
for (int i = checkedLength; i >= 0; i--) {
Certificate cert = chain[i];
diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java
index b6ed37cc5a3..954b90d15dd 100644
--- a/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java
@@ -39,6 +39,7 @@ import java.security.cert.Certificate;
import javax.net.ssl.*;
import sun.security.provider.certpath.AlgorithmChecker;
+import sun.security.validator.Validator;
/**
* The new X509 key manager implementation. The main differences to the
@@ -661,6 +662,15 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager
return CheckResult.OK;
}
+
+ public String getValidator() {
+ if (this == CLIENT) {
+ return Validator.VAR_TLS_CLIENT;
+ } else if (this == SERVER) {
+ return Validator.VAR_TLS_SERVER;
+ }
+ return Validator.VAR_GENERIC;
+ }
}
// enum for the result of the extension check
@@ -774,7 +784,8 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager
// check the algorithm constraints
if (constraints != null &&
- !conformsToAlgorithmConstraints(constraints, chain)) {
+ !conformsToAlgorithmConstraints(constraints, chain,
+ checkType.getValidator())) {
if (useDebug) {
debug.println("Ignoring alias " + alias +
@@ -811,9 +822,10 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager
}
private static boolean conformsToAlgorithmConstraints(
- AlgorithmConstraints constraints, Certificate[] chain) {
+ AlgorithmConstraints constraints, Certificate[] chain,
+ String variant) {
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
+ AlgorithmChecker checker = new AlgorithmChecker(constraints, null, variant);
try {
checker.init(false);
} catch (CertPathValidatorException cpve) {
diff --git a/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java b/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java
deleted file mode 100644
index 23880f7c6aa..00000000000
--- a/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.util;
-
-import java.security.Timestamp;
-import java.security.cert.X509Certificate;
-import java.util.Date;
-
-/**
- * This class is a wrapper for keeping state and passing objects between PKIX,
- * AlgorithmChecker, and DisabledAlgorithmConstraints.
- */
-public class CertConstraintParameters {
- // A certificate being passed to check against constraints.
- private final X509Certificate cert;
- // This is true if the trust anchor in the certificate chain matches a cert
- // in AnchorCertificates
- private final boolean trustedMatch;
- // PKIXParameter date
- private final Date pkixDate;
- // Timestamp of the signed JAR file
- private final Timestamp jarTimestamp;
-
- public CertConstraintParameters(X509Certificate c, boolean match,
- Date pkixdate, Timestamp jarTime) {
- cert = c;
- trustedMatch = match;
- pkixDate = pkixdate;
- jarTimestamp = jarTime;
- }
-
- public CertConstraintParameters(X509Certificate c) {
- this(c, false, null, null);
- }
-
- // Returns if the trust anchor has a match if anchor checking is enabled.
- public boolean isTrustedMatch() {
- return trustedMatch;
- }
-
- public X509Certificate getCertificate() {
- return cert;
- }
-
- public Date getPKIXParamDate() {
- return pkixDate;
- }
-
- public Timestamp getJARTimestamp() {
- return jarTimestamp;
- }
-
-}
diff --git a/jdk/src/java.base/share/classes/sun/security/util/ConstraintsParameters.java b/jdk/src/java.base/share/classes/sun/security/util/ConstraintsParameters.java
new file mode 100644
index 00000000000..84318654557
--- /dev/null
+++ b/jdk/src/java.base/share/classes/sun/security/util/ConstraintsParameters.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.util;
+
+import sun.security.validator.Validator;
+
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.Timestamp;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+/**
+ * This class contains parameters for checking against constraints that extend
+ * past the publicly available parameters in java.security.AlgorithmConstraints.
+
+ * This is currently on passed between between PKIX, AlgorithmChecker,
+ * and DisabledAlgorithmConstraints.
+ */
+public class ConstraintsParameters {
+ /*
+ * The below 3 values are used the same as the permit() methods
+ * published in java.security.AlgorithmConstraints.
+ */
+ // Algorithm string to be checked against constraints
+ private final String algorithm;
+ // AlgorithmParameters to the algorithm being checked
+ private final AlgorithmParameters algParams;
+ // Public Key being checked against constraints
+ private final Key publicKey;
+
+ /*
+ * New values that are checked against constraints that the current public
+ * API does not support.
+ */
+ // A certificate being passed to check against constraints.
+ private final X509Certificate cert;
+ // This is true if the trust anchor in the certificate chain matches a cert
+ // in AnchorCertificates
+ private final boolean trustedMatch;
+ // PKIXParameter date
+ private final Date pkixDate;
+ // Timestamp of the signed JAR file
+ private final Timestamp jarTimestamp;
+ private final String variant;
+
+ public ConstraintsParameters(X509Certificate c, boolean match,
+ Date pkixdate, Timestamp jarTime, String variant) {
+ cert = c;
+ trustedMatch = match;
+ pkixDate = pkixdate;
+ jarTimestamp = jarTime;
+ this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+ algorithm = null;
+ algParams = null;
+ publicKey = null;
+ }
+
+ public ConstraintsParameters(String algorithm, AlgorithmParameters params,
+ Key key, String variant) {
+ this.algorithm = algorithm;
+ algParams = params;
+ this.publicKey = key;
+ cert = null;
+ trustedMatch = false;
+ pkixDate = null;
+ jarTimestamp = null;
+ this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+ }
+
+
+ public ConstraintsParameters(X509Certificate c) {
+ this(c, false, null, null,
+ Validator.VAR_GENERIC);
+ }
+
+ public ConstraintsParameters(Timestamp jarTime) {
+ this(null, false, null, jarTime, Validator.VAR_GENERIC);
+ }
+
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ public AlgorithmParameters getAlgParams() {
+ return algParams;
+ }
+
+ public Key getPublicKey() {
+ return publicKey;
+ }
+ // Returns if the trust anchor has a match if anchor checking is enabled.
+ public boolean isTrustedMatch() {
+ return trustedMatch;
+ }
+
+ public X509Certificate getCertificate() {
+ return cert;
+ }
+
+ public Date getPKIXParamDate() {
+ return pkixDate;
+ }
+
+ public Timestamp getJARTimestamp() {
+ return jarTimestamp;
+ }
+
+ public String getVariant() {
+ return variant;
+ }
+}
diff --git a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
index 73914fe30ae..a8b4a6f0a40 100644
--- a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
+++ b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package sun.security.util;
+import sun.security.validator.Validator;
+
import java.security.CryptoPrimitive;
import java.security.AlgorithmParameters;
import java.security.Key;
@@ -32,10 +34,12 @@ import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -100,12 +104,6 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
@Override
public final boolean permits(Set primitives,
String algorithm, AlgorithmParameters parameters) {
-
- if (primitives == null || primitives.isEmpty()) {
- throw new IllegalArgumentException(
- "No cryptographic primitive specified");
- }
-
return checkAlgorithm(disabledAlgorithms, algorithm, decomposer);
}
@@ -133,6 +131,18 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return checkConstraints(primitives, algorithm, key, parameters);
}
+ public final void permits(ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ permits(cp.getAlgorithm(), cp);
+ }
+
+ public final void permits(String algorithm, Key key,
+ AlgorithmParameters params, String variant)
+ throws CertPathValidatorException {
+ permits(algorithm, new ConstraintsParameters(algorithm, params, key,
+ (variant == null) ? Validator.VAR_GENERIC : variant));
+ }
+
/*
* Check if a x509Certificate object is permitted. Check if all
* algorithms are allowed, certificate constraints, and the
@@ -140,18 +150,10 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
*
* Uses new style permit() which throws exceptions.
*/
- public final void permits(Set primitives,
- CertConstraintParameters cp) throws CertPathValidatorException {
- checkConstraints(primitives, cp);
- }
- /*
- * Check if Certificate object is within the constraints.
- * Uses new style permit() which throws exceptions.
- */
- public final void permits(Set primitives,
- X509Certificate cert) throws CertPathValidatorException {
- checkConstraints(primitives, new CertConstraintParameters(cert));
+ public final void permits(String algorithm, ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ algorithmConstraints.permits(algorithm, cp);
}
// Check if a string is contained inside the property
@@ -174,7 +176,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
throw new IllegalArgumentException("The key cannot be null");
}
- // check the signature algorithm
+ // check the signature algorithm with parameters
if (algorithm != null && algorithm.length() != 0) {
if (!permits(primitives, algorithm, parameters)) {
return false;
@@ -190,36 +192,6 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return algorithmConstraints.permits(key);
}
- /*
- * Check algorithm constraints with Certificate
- * Uses new style permit() which throws exceptions.
- */
- private void checkConstraints(Set primitives,
- CertConstraintParameters cp) throws CertPathValidatorException {
-
- X509Certificate cert = cp.getCertificate();
- String algorithm = cert.getSigAlgName();
-
- // Check signature algorithm is not disabled
- if (!permits(primitives, algorithm, null)) {
- throw new CertPathValidatorException(
- "Algorithm constraints check failed on disabled "+
- "signature algorithm: " + algorithm,
- null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
- }
-
- // Check key algorithm is not disabled
- if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) {
- throw new CertPathValidatorException(
- "Algorithm constraints check failed on disabled "+
- "public key algorithm: " + algorithm,
- null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
- }
-
- // Check the certificate and key constraints
- algorithmConstraints.permits(cp);
-
- }
/**
* Key and Certificate Constraints
@@ -234,13 +206,13 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* 'true' means the operation is allowed.
* 'false' means it failed the constraints and is disallowed.
*
- * When passing CertConstraintParameters through permit(), an exception
+ * When passing ConstraintsParameters through permit(), an exception
* will be thrown on a failure to better identify why the operation was
* disallowed.
*/
private static class Constraints {
- private Map> constraintsMap = new HashMap<>();
+ private Map> constraintsMap = new HashMap<>();
private static class Holder {
private static final Pattern DENY_AFTER_PATTERN = Pattern.compile(
@@ -260,23 +232,22 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
// Check if constraint is a complete disabling of an
// algorithm or has conditions.
- String algorithm;
- String policy;
int space = constraintEntry.indexOf(' ');
- if (space > 0) {
- algorithm = AlgorithmDecomposer.hashName(
- constraintEntry.substring(0, space).
- toUpperCase(Locale.ENGLISH));
- policy = constraintEntry.substring(space + 1);
- } else {
- algorithm = constraintEntry.toUpperCase(Locale.ENGLISH);
- if (!constraintsMap.containsKey(algorithm)) {
- constraintsMap.putIfAbsent(algorithm,
- new HashSet<>());
- }
+ String algorithm = AlgorithmDecomposer.hashName(
+ ((space > 0 ? constraintEntry.substring(0, space) :
+ constraintEntry).
+ toUpperCase(Locale.ENGLISH)));
+ List constraintList =
+ constraintsMap.getOrDefault(algorithm,
+ new ArrayList<>(1));
+ constraintsMap.putIfAbsent(algorithm, constraintList);
+ if (space <= 0) {
+ constraintList.add(new DisabledConstraint(algorithm));
continue;
}
+ String policy = constraintEntry.substring(space + 1);
+
// Convert constraint conditions into Constraint classes
Constraint c, lastConstraint = null;
// Allow only one jdkCA entry per constraint entry
@@ -315,7 +286,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
c = new jdkCAConstraint(algorithm);
jdkCALimit = true;
- } else if(entry.startsWith("denyAfter") &&
+ } else if (entry.startsWith("denyAfter") &&
(matcher = Holder.DENY_AFTER_PATTERN.matcher(entry))
.matches()) {
if (debug != null) {
@@ -332,6 +303,12 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
c = new DenyAfterConstraint(algorithm, year, month,
day);
denyAfterLimit = true;
+ } else if (entry.startsWith("usage")) {
+ String s[] = (entry.substring(5)).trim().split(" ");
+ c = new UsageConstraint(algorithm, s);
+ if (debug != null) {
+ debug.println("Constraints usage length is " + s.length);
+ }
} else {
throw new IllegalArgumentException("Error in security" +
" property. Constraint unknown: " + entry);
@@ -340,11 +317,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
// Link multiple conditions for a single constraint
// into a linked list.
if (lastConstraint == null) {
- if (!constraintsMap.containsKey(algorithm)) {
- constraintsMap.putIfAbsent(algorithm,
- new HashSet<>());
- }
- constraintsMap.get(algorithm).add(c);
+ constraintList.add(c);
} else {
lastConstraint.nextConstraint = c;
}
@@ -354,17 +327,17 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
// Get applicable constraints based off the signature algorithm
- private Set getConstraints(String algorithm) {
+ private List getConstraints(String algorithm) {
return constraintsMap.get(algorithm);
}
// Check if KeySizeConstraints permit the specified key
public boolean permits(Key key) {
- Set set = getConstraints(key.getAlgorithm());
- if (set == null) {
+ List list = getConstraints(key.getAlgorithm());
+ if (list == null) {
return true;
}
- for (Constraint constraint : set) {
+ for (Constraint constraint : list) {
if (!constraint.permits(key)) {
if (debug != null) {
debug.println("keySizeConstraint: failed key " +
@@ -377,31 +350,35 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
// Check if constraints permit this cert.
- public void permits(CertConstraintParameters cp)
+ public void permits(String algorithm, ConstraintsParameters cp)
throws CertPathValidatorException {
X509Certificate cert = cp.getCertificate();
if (debug != null) {
- debug.println("Constraints.permits(): " + cert.getSigAlgName());
+ debug.println("Constraints.permits(): " + algorithm +
+ " Variant: " + cp.getVariant());
}
// Get all signature algorithms to check for constraints
- Set algorithms =
- AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName());
- if (algorithms == null || algorithms.isEmpty()) {
- return;
+ Set algorithms = new HashSet<>();
+ if (algorithm != null) {
+ algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm));
}
- // Attempt to add the public key algorithm to the set
- algorithms.add(cert.getPublicKey().getAlgorithm());
-
+ // Attempt to add the public key algorithm if cert provided
+ if (cert != null) {
+ algorithms.add(cert.getPublicKey().getAlgorithm());
+ }
+ if (cp.getPublicKey() != null) {
+ algorithms.add(cp.getPublicKey().getAlgorithm());
+ }
// Check all applicable constraints
- for (String algorithm : algorithms) {
- Set set = getConstraints(algorithm);
- if (set == null) {
+ for (String alg : algorithms) {
+ List list = getConstraints(alg);
+ if (list == null) {
continue;
}
- for (Constraint constraint : set) {
+ for (Constraint constraint : list) {
constraint.permits(cp);
}
}
@@ -467,17 +444,17 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
/**
* Check if an algorithm constraint is permitted with a given
- * CertConstraintParameters.
+ * ConstraintsParameters.
*
* If the check inside of {@code permits()} fails, it must call
- * {@code next()} with the same {@code CertConstraintParameters}
+ * {@code next()} with the same {@code ConstraintsParameters}
* parameter passed if multiple constraints need to be checked.
*
* @param cp CertConstraintParameter containing certificate info
* @throws CertPathValidatorException if constraint disallows.
*
*/
- public abstract void permits(CertConstraintParameters cp)
+ public abstract void permits(ConstraintsParameters cp)
throws CertPathValidatorException;
/**
@@ -491,12 +468,12 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* were disallowed, the last constraint will throw
* {@code CertPathValidatorException}.
*
- * @param cp CertConstraintParameters
+ * @param cp ConstraintsParameters
* @return 'true' if constraint allows the operation, 'false' if
* we are at the end of the constraint list or,
* {@code nextConstraint} is null.
*/
- boolean next(CertConstraintParameters cp)
+ boolean next(ConstraintsParameters cp)
throws CertPathValidatorException {
if (nextConstraint != null) {
nextConstraint.permits(cp);
@@ -525,6 +502,14 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
return false;
}
+
+ String extendedMsg(ConstraintsParameters cp) {
+ return (cp.getCertificate() == null ? "." :
+ " used with certificate: " +
+ cp.getCertificate().getSubjectX500Principal() +
+ (cp.getVariant() != Validator.VAR_GENERIC ?
+ ". Usage was " + cp.getVariant() : "."));
+ }
}
/*
@@ -537,11 +522,11 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
/*
- * Check if CertConstraintParameters has a trusted match, if it does
+ * Check if ConstraintsParameters has a trusted match, if it does
* call next() for any following constraints. If it does not, exit
* as this constraint(s) does not restrict the operation.
*/
- public void permits(CertConstraintParameters cp)
+ public void permits(ConstraintsParameters cp)
throws CertPathValidatorException {
if (debug != null) {
debug.println("jdkCAConstraints.permits(): " + algorithm);
@@ -554,8 +539,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
throw new CertPathValidatorException(
"Algorithm constraints check failed on certificate " +
- "anchor limits. " + algorithm + " used with " +
- cp.getCertificate().getSubjectX500Principal(),
+ "anchor limits. " + algorithm + extendedMsg(cp),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
}
@@ -615,7 +599,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* constraints. Throw an exception if this is the last constraint.
*/
@Override
- public void permits(CertConstraintParameters cp)
+ public void permits(ConstraintsParameters cp)
throws CertPathValidatorException {
Date currentDate;
String errmsg;
@@ -628,7 +612,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
errmsg = "PKIXParameter date: ";
} else {
currentDate = new Date();
- errmsg = "Certificate date: ";
+ errmsg = "Current date: ";
}
if (!denyAfterDate.after(currentDate)) {
@@ -637,9 +621,9 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
throw new CertPathValidatorException(
"denyAfter constraint check failed: " + algorithm +
- " used with Constraint date: " +
- dateFormat.format(denyAfterDate) + "; "
- + errmsg + dateFormat.format(currentDate),
+ " used with Constraint date: " +
+ dateFormat.format(denyAfterDate) + "; " + errmsg +
+ dateFormat.format(currentDate) + extendedMsg(cp),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
}
@@ -660,6 +644,48 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
}
}
+ /*
+ * The usage constraint is for the "usage" keyword. It checks against the
+ * variant value in ConstraintsParameters.
+ */
+ private static class UsageConstraint extends Constraint {
+ String[] usages;
+
+ UsageConstraint(String algorithm, String[] usages) {
+ this.algorithm = algorithm;
+ this.usages = usages;
+ }
+
+ public void permits(ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ for (String usage : usages) {
+
+ String v = null;
+ if (usage.compareToIgnoreCase("TLSServer") == 0) {
+ v = Validator.VAR_TLS_SERVER;
+ } else if (usage.compareToIgnoreCase("TLSClient") == 0) {
+ v = Validator.VAR_TLS_CLIENT;
+ } else if (usage.compareToIgnoreCase("SignedJAR") == 0) {
+ v = Validator.VAR_PLUGIN_CODE_SIGNING;
+ }
+
+ if (debug != null) {
+ debug.println("Checking if usage constraint " + v +
+ " matches " + cp.getVariant());
+ }
+ if (cp.getVariant().compareTo(v) == 0) {
+ if (next(cp)) {
+ return;
+ }
+ throw new CertPathValidatorException("Usage constraint " +
+ usage + " check failed: " + algorithm +
+ extendedMsg(cp),
+ null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+ }
+ }
+ }
+ }
+
/*
* This class contains constraints dealing with the key size
* support limits per algorithm. e.g. "keySize <= 1024"
@@ -713,17 +739,22 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* constraint Any permitted constraint will exit the linked list
* to allow the operation.
*/
- public void permits(CertConstraintParameters cp)
+ public void permits(ConstraintsParameters cp)
throws CertPathValidatorException {
- if (!permitsImpl(cp.getCertificate().getPublicKey())) {
+ Key key = null;
+ if (cp.getPublicKey() != null) {
+ key = cp.getPublicKey();
+ } else if (cp.getCertificate() != null) {
+ key = cp.getCertificate().getPublicKey();
+ }
+ if (key != null && !permitsImpl(key)) {
if (nextConstraint != null) {
nextConstraint.permits(cp);
return;
}
throw new CertPathValidatorException(
"Algorithm constraints check failed on keysize limits. "
- + algorithm + " " + size + "bit key used with "
- + cp.getCertificate().getSubjectX500Principal(),
+ + algorithm + " " + size + "bit key" + extendedMsg(cp),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
}
@@ -762,5 +793,26 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
return true;
}
}
+
+ /*
+ * This constraint is used for the complete disabling of the algorithm.
+ */
+ private static class DisabledConstraint extends Constraint {
+ DisabledConstraint(String algo) {
+ algorithm = algo;
+ }
+
+ public void permits(ConstraintsParameters cp)
+ throws CertPathValidatorException {
+ throw new CertPathValidatorException(
+ "Algorithm constraints check failed on disabled " +
+ "algorithm: " + algorithm + extendedMsg(cp),
+ null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+ }
+
+ public boolean permits(Key key) {
+ return false;
+ }
+ }
}
diff --git a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java
index f8022c5ca94..2fe1c7ee91e 100644
--- a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java
+++ b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* 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,25 +28,23 @@ package sun.security.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.CodeSigner;
-import java.security.CryptoPrimitive;
+import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
+import java.security.Timestamp;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.Base64;
-import java.util.Collections;
-import java.util.EnumSet;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarException;
import java.util.jar.JarFile;
@@ -61,9 +59,6 @@ public class SignatureFileVerifier {
/* Are we debugging ? */
private static final Debug debug = Debug.getInstance("jar");
- private static final Set DIGEST_PRIMITIVE_SET =
- Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
-
private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
new DisabledAlgorithmConstraints(
DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
@@ -97,6 +92,14 @@ public class SignatureFileVerifier {
/* for generating certpath objects */
private CertificateFactory certificateFactory = null;
+ /** Algorithms that have been checked if they are weak. */
+ private Map permittedAlgs= new HashMap<>();
+
+ /** TSA timestamp of signed jar. The newest timestamp is used. If there
+ * was no TSA timestamp used when signed, current time is used ("null").
+ */
+ private Timestamp timestamp = null;
+
/**
* Create the named SignatureFileVerifier.
*
@@ -222,15 +225,8 @@ public class SignatureFileVerifier {
/** get digest from cache */
- private MessageDigest getDigest(String algorithm) throws SignatureException {
- // check that algorithm is not restricted
- if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, algorithm, null)) {
- SignatureException e =
- new SignatureException("SignatureFile check failed. " +
- "Disabled algorithm used: " + algorithm);
- throw e;
- }
-
+ private MessageDigest getDigest(String algorithm)
+ throws SignatureException {
if (createdDigests == null)
createdDigests = new HashMap<>();
@@ -302,6 +298,27 @@ public class SignatureFileVerifier {
if (newSigners == null)
return;
+ /*
+ * Look for the latest timestamp in the signature block. If an entry
+ * has no timestamp, use current time (aka null).
+ */
+ for (CodeSigner s: newSigners) {
+ if (debug != null) {
+ debug.println("Gathering timestamp for: " + s.toString());
+ }
+ if (s.getTimestamp() == null) {
+ timestamp = null;
+ break;
+ } else if (timestamp == null) {
+ timestamp = s.getTimestamp();
+ } else {
+ if (timestamp.getTimestamp().before(
+ s.getTimestamp().getTimestamp())) {
+ timestamp = s.getTimestamp();
+ }
+ }
+ }
+
Iterator> entries =
sf.getEntries().entrySet().iterator();
@@ -344,6 +361,68 @@ public class SignatureFileVerifier {
updateSigners(newSigners, signers, JarFile.MANIFEST_NAME);
}
+ /**
+ * Check if algorithm is permitted using the permittedAlgs Map.
+ * If the algorithm is not in the map, check against disabled algorithms and
+ * store the result. If the algorithm is in the map use that result.
+ * False is returned for weak algorithm, true for good algorithms.
+ */
+ boolean permittedCheck(String key, String algorithm) {
+ Boolean permitted = permittedAlgs.get(algorithm);
+ if (permitted == null) {
+ try {
+ JAR_DISABLED_CHECK.permits(algorithm,
+ new ConstraintsParameters(timestamp));
+ } catch(GeneralSecurityException e) {
+ permittedAlgs.put(algorithm, Boolean.FALSE);
+ permittedAlgs.put(key.toUpperCase(), Boolean.FALSE);
+ if (debug != null) {
+ if (e.getMessage() != null) {
+ debug.println(key + ": " + e.getMessage());
+ } else {
+ debug.println(key + ": " + algorithm +
+ " was disabled, no exception msg given.");
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ permittedAlgs.put(algorithm, Boolean.TRUE);
+ return true;
+ }
+
+ // Algorithm has already been checked, return the value from map.
+ return permitted.booleanValue();
+ }
+
+ /**
+ * With a given header (*-DIGEST*), return a string that lists all the
+ * algorithms associated with the header.
+ * If there are none, return "Unknown Algorithm".
+ */
+ String getWeakAlgorithms(String header) {
+ String w = "";
+ try {
+ for (String key : permittedAlgs.keySet()) {
+ if (key.endsWith(header)) {
+ w += key.substring(0, key.length() - header.length()) + " ";
+ }
+ }
+ } catch (RuntimeException e) {
+ w = "Unknown Algorithm(s). Error processing " + header + ". " +
+ e.getMessage();
+ }
+
+ // This means we have an error in finding weak algorithms, run in
+ // debug mode to see permittedAlgs map's values.
+ if (w.length() == 0) {
+ return "Unknown Algorithm(s)";
+ }
+
+ return w;
+ }
+
/**
* See if the whole manifest was signed.
*/
@@ -354,6 +433,7 @@ public class SignatureFileVerifier {
{
Attributes mattr = sf.getMainAttributes();
boolean manifestSigned = false;
+ boolean weakAlgs = true;
// go through all the attributes and process *-Digest-Manifest entries
for (Map.Entry